is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+#
+# Qt Help Project / Custom Filters.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+#
+# Qt Help Project / Filter Attributes.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 1
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvances is that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = RTF
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = YES
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH = ../..
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = __DOXYGEN__ __AVR32_ABI_COMPILER__ __attribute__()= __GNUC__=4
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = gif
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/atmel-samd/asf/common/services/usb/class/msc/doxygen/common.services.usb.class.msc.protocol/doxygen_module_mainpage.h b/atmel-samd/asf/common/services/usb/class/msc/doxygen/common.services.usb.class.msc.protocol/doxygen_module_mainpage.h
new file mode 100644
index 0000000000..26566747f8
--- /dev/null
+++ b/atmel-samd/asf/common/services/usb/class/msc/doxygen/common.services.usb.class.msc.protocol/doxygen_module_mainpage.h
@@ -0,0 +1,58 @@
+
+/**
+ * Copyright (c) 2012 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * 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
+ * EXPRESSLY AND SPECIFICALLY 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.
+ *
+ * \asf_license_stop
+ *
+ * \mainpage
+ *
+ * \section intro Introduction
+ * This documentation has been automatically generated, and documents the source
+ * code found in the Atmel Software Framework (ASF).
+ * Use the above menu to navigate in the documentation, or use the links below:
+ *
+ *
+ * \section main_licence License
+ *
+ * \section contactinfo Contact Information
+ * For further information, visit Atmel.\n
+ *
+ */
diff --git a/atmel-samd/asf/common/services/usb/class/msc/sbc_protocol.h b/atmel-samd/asf/common/services/usb/class/msc/sbc_protocol.h
new file mode 100644
index 0000000000..082b735fa6
--- /dev/null
+++ b/atmel-samd/asf/common/services/usb/class/msc/sbc_protocol.h
@@ -0,0 +1,173 @@
+/**
+ * \file
+ *
+ * \brief SCSI Block Commands
+ *
+ * This file contains definitions of some of the commands found in the
+ * SCSI SBC-2 standard.
+ *
+ * Note that the SBC specification depends on several commands defined
+ * by the SCSI Primary Commands (SPC) standard. Each version of the SBC
+ * standard is meant to be used in conjunction with a specific version
+ * of the SPC standard, as follows:
+ * - SBC depends on SPC
+ * - SBC-2 depends on SPC-3
+ * - SBC-3 depends on SPC-4
+ *
+ * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * 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
+ * EXPRESSLY AND SPECIFICALLY 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.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Atmel Support
+ */
+#ifndef _SBC_PROTOCOL_H_
+#define _SBC_PROTOCOL_H_
+
+
+/**
+ * \ingroup usb_msc_protocol
+ * \defgroup usb_sbc_protocol SCSI Block Commands protocol definitions
+ *
+ * @{
+ */
+
+//! \name SCSI commands defined by SBC-2
+//@{
+#define SBC_FORMAT_UNIT 0x04
+#define SBC_READ6 0x08
+#define SBC_WRITE6 0x0A
+#define SBC_START_STOP_UNIT 0x1B
+#define SBC_READ_CAPACITY10 0x25
+#define SBC_READ10 0x28
+#define SBC_WRITE10 0x2A
+#define SBC_VERIFY10 0x2F
+//@}
+
+//! \name SBC-2 Mode page definitions
+//@{
+
+enum scsi_sbc_mode {
+ SCSI_MS_MODE_RW_ERR_RECOV = 0x01, //!< Read-Write Error Recovery mode page
+ SCSI_MS_MODE_FORMAT_DEVICE = 0x03, //!< Format Device mode page
+ SCSI_MS_MODE_FLEXIBLE_DISK = 0x05, //!< Flexible Disk mode page
+ SCSI_MS_MODE_CACHING = 0x08, //!< Caching mode page
+};
+
+
+//! \name SBC-2 Device-Specific Parameter
+//@{
+#define SCSI_MS_SBC_WP 0x80 //!< Write Protected
+#define SCSI_MS_SBC_DPOFUA 0x10 //!< DPO and FUA supported
+//@}
+
+/**
+ * \brief SBC-2 Short LBA mode parameter block descriptor
+ */
+struct sbc_slba_block_desc {
+ be32_t nr_blocks; //!< Number of Blocks
+ be32_t block_len; //!< Block Length
+#define SBC_SLBA_BLOCK_LEN_MASK 0x00FFFFFFU //!< Mask reserved bits
+};
+
+/**
+ * \brief SBC-2 Caching mode page
+ */
+struct sbc_caching_mode_page {
+ uint8_t page_code;
+ uint8_t page_length;
+ uint8_t flags2;
+#define SBC_MP_CACHE_IC (1 << 7) //!< Initiator Control
+#define SBC_MP_CACHE_ABPF (1 << 6) //!< Abort Pre-Fetch
+#define SBC_MP_CACHE_CAP (1 << 5) //!< Catching Analysis Permitted
+#define SBC_MP_CACHE_DISC (1 << 4) //!< Discontinuity
+#define SBC_MP_CACHE_SIZE (1 << 3) //!< Size enable
+#define SBC_MP_CACHE_WCE (1 << 2) //!< Write back Cache Enable
+#define SBC_MP_CACHE_MF (1 << 1) //!< Multiplication Factor
+#define SBC_MP_CACHE_RCD (1 << 0) //!< Read Cache Disable
+ uint8_t retention;
+ be16_t dis_pf_transfer_len;
+ be16_t min_prefetch;
+ be16_t max_prefetch;
+ be16_t max_prefetch_ceil;
+ uint8_t flags12;
+#define SBC_MP_CACHE_FSW (1 << 7) //!< Force Sequential Write
+#define SBC_MP_CACHE_LBCSS (1 << 6) //!< Logical Blk Cache Seg Sz
+#define SBC_MP_CACHE_DRA (1 << 5) //!< Disable Read-Ahead
+#define SBC_MP_CACHE_NV_DIS (1 << 0) //!< Non-Volatile Cache Disable
+ uint8_t nr_cache_segments;
+ be16_t cache_segment_size;
+ uint8_t reserved[4];
+};
+
+/**
+ * \brief SBC-2 Read-Write Error Recovery mode page
+ */
+struct sbc_rdwr_error_recovery_mode_page {
+ uint8_t page_code;
+ uint8_t page_length;
+#define SPC_MP_RW_ERR_RECOV_PAGE_LENGTH 0x0A
+ uint8_t flags1;
+#define SBC_MP_RW_ERR_RECOV_AWRE (1 << 7)
+#define SBC_MP_RW_ERR_RECOV_ARRE (1 << 6)
+#define SBC_MP_RW_ERR_RECOV_TB (1 << 5)
+#define SBC_MP_RW_ERR_RECOV_RC (1 << 4)
+#define SBC_MP_RW_ERR_RECOV_ERR (1 << 3)
+#define SBC_MP_RW_ERR_RECOV_PER (1 << 2)
+#define SBC_MP_RW_ERR_RECOV_DTE (1 << 1)
+#define SBC_MP_RW_ERR_RECOV_DCR (1 << 0)
+ uint8_t read_retry_count;
+ uint8_t correction_span;
+ uint8_t head_offset_count;
+ uint8_t data_strobe_offset_count;
+ uint8_t flags2;
+ uint8_t write_retry_count;
+ uint8_t flags3;
+ be16_t recovery_time_limit;
+};
+//@}
+
+/**
+ * \brief SBC-2 READ CAPACITY (10) parameter data
+ */
+struct sbc_read_capacity10_data {
+ be32_t max_lba; //!< LBA of last logical block
+ be32_t block_len; //!< Number of bytes in the last logical block
+};
+
+//@}
+
+#endif // _SBC_PROTOCOL_H_
diff --git a/atmel-samd/asf/common/services/usb/class/msc/spc_protocol.h b/atmel-samd/asf/common/services/usb/class/msc/spc_protocol.h
new file mode 100644
index 0000000000..84c4dd50a9
--- /dev/null
+++ b/atmel-samd/asf/common/services/usb/class/msc/spc_protocol.h
@@ -0,0 +1,337 @@
+/**
+ * \file
+ *
+ * \brief SCSI Primary Commands
+ *
+ * This file contains definitions of some of the commands found in the
+ * SPC-2 standard.
+ *
+ * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * 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
+ * EXPRESSLY AND SPECIFICALLY 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.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Atmel Support
+ */
+#ifndef _SPC_PROTOCOL_H_
+#define _SPC_PROTOCOL_H_
+
+
+/**
+ * \ingroup usb_msc_protocol
+ * \defgroup usb_spc_protocol SCSI Primary Commands protocol definitions
+ *
+ * @{
+ */
+
+//! \name SCSI commands defined by SPC-2
+//@{
+#define SPC_TEST_UNIT_READY 0x00
+#define SPC_REQUEST_SENSE 0x03
+#define SPC_INQUIRY 0x12
+#define SPC_MODE_SELECT6 0x15
+#define SPC_MODE_SENSE6 0x1A
+#define SPC_SEND_DIAGNOSTIC 0x1D
+#define SPC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
+#define SPC_MODE_SENSE10 0x5A
+#define SPC_REPORT_LUNS 0xA0
+//@}
+
+//! \brief May be set in byte 0 of the INQUIRY CDB
+//@{
+//! Enable Vital Product Data
+#define SCSI_INQ_REQ_EVPD 0x01
+//! Command Support Data specified by the PAGE OR OPERATION CODE field
+#define SCSI_INQ_REQ_CMDT 0x02
+//@}
+
+COMPILER_PACK_SET(1)
+
+/**
+ * \brief SCSI Standard Inquiry data structure
+ */
+struct scsi_inquiry_data {
+ uint8_t pq_pdt; //!< Peripheral Qual / Peripheral Dev Type
+#define SCSI_INQ_PQ_CONNECTED 0x00 //!< Peripheral connected
+#define SCSI_INQ_PQ_NOT_CONN 0x20 //!< Peripheral not connected
+#define SCSI_INQ_PQ_NOT_SUPP 0x60 //!< Peripheral not supported
+#define SCSI_INQ_DT_DIR_ACCESS 0x00 //!< Direct Access (SBC)
+#define SCSI_INQ_DT_SEQ_ACCESS 0x01 //!< Sequential Access
+#define SCSI_INQ_DT_PRINTER 0x02 //!< Printer
+#define SCSI_INQ_DT_PROCESSOR 0x03 //!< Processor device
+#define SCSI_INQ_DT_WRITE_ONCE 0x04 //!< Write-once device
+#define SCSI_INQ_DT_CD_DVD 0x05 //!< CD/DVD device
+#define SCSI_INQ_DT_OPTICAL 0x07 //!< Optical Memory
+#define SCSI_INQ_DT_MC 0x08 //!< Medium Changer
+#define SCSI_INQ_DT_ARRAY 0x0c //!< Storage Array Controller
+#define SCSI_INQ_DT_ENCLOSURE 0x0d //!< Enclosure Services
+#define SCSI_INQ_DT_RBC 0x0e //!< Simplified Direct Access
+#define SCSI_INQ_DT_OCRW 0x0f //!< Optical card reader/writer
+#define SCSI_INQ_DT_BCC 0x10 //!< Bridge Controller Commands
+#define SCSI_INQ_DT_OSD 0x11 //!< Object-based Storage
+#define SCSI_INQ_DT_NONE 0x1f //!< No Peripheral
+ uint8_t flags1; //!< Flags (byte 1)
+#define SCSI_INQ_RMB 0x80 //!< Removable Medium
+ uint8_t version; //!< Version
+#define SCSI_INQ_VER_NONE 0x00 //!< No standards conformance
+#define SCSI_INQ_VER_SPC 0x03 //!< SCSI Primary Commands (link to SBC)
+#define SCSI_INQ_VER_SPC2 0x04 //!< SCSI Primary Commands - 2 (link to SBC-2)
+#define SCSI_INQ_VER_SPC3 0x05 //!< SCSI Primary Commands - 3 (link to SBC-2)
+#define SCSI_INQ_VER_SPC4 0x06 //!< SCSI Primary Commands - 4 (link to SBC-3)
+ uint8_t flags3; //!< Flags (byte 3)
+#define SCSI_INQ_NORMACA 0x20 //!< Normal ACA Supported
+#define SCSI_INQ_HISUP 0x10 //!< Hierarchal LUN addressing
+#define SCSI_INQ_RSP_SPC2 0x02 //!< SPC-2 / SPC-3 response format
+ uint8_t addl_len; //!< Additional Length (n-4)
+#define SCSI_INQ_ADDL_LEN(tot) ((tot)-5) //!< Total length is \a tot
+ uint8_t flags5; //!< Flags (byte 5)
+#define SCSI_INQ_SCCS 0x80
+ uint8_t flags6; //!< Flags (byte 6)
+#define SCSI_INQ_BQUE 0x80
+#define SCSI_INQ_ENCSERV 0x40
+#define SCSI_INQ_MULTIP 0x10
+#define SCSI_INQ_MCHGR 0x08
+#define SCSI_INQ_ADDR16 0x01
+ uint8_t flags7; //!< Flags (byte 7)
+#define SCSI_INQ_WBUS16 0x20
+#define SCSI_INQ_SYNC 0x10
+#define SCSI_INQ_LINKED 0x08
+#define SCSI_INQ_CMDQUE 0x02
+ uint8_t vendor_id[8]; //!< T10 Vendor Identification
+ uint8_t product_id[16]; //!< Product Identification
+ uint8_t product_rev[4]; //!< Product Revision Level
+};
+
+/**
+ * \brief SCSI Standard Request sense data structure
+ */
+struct scsi_request_sense_data {
+ /* 1st byte: REQUEST SENSE response flags*/
+ uint8_t valid_reponse_code;
+#define SCSI_SENSE_VALID 0x80 //!< Indicates the INFORMATION field contains valid information
+#define SCSI_SENSE_RESPONSE_CODE_MASK 0x7F
+#define SCSI_SENSE_CURRENT 0x70 //!< Response code 70h (current errors)
+#define SCSI_SENSE_DEFERRED 0x71
+
+ /* 2nd byte */
+ uint8_t obsolete;
+
+ /* 3rd byte */
+ uint8_t sense_flag_key;
+#define SCSI_SENSE_FILEMARK 0x80 //!< Indicates that the current command has read a filemark or setmark.
+#define SCSI_SENSE_EOM 0x40 //!< Indicates that an end-of-medium condition exists.
+#define SCSI_SENSE_ILI 0x20 //!< Indicates that the requested logical block length did not match the logical block length of the data on the medium.
+#define SCSI_SENSE_RESERVED 0x10 //!< Reserved
+#define SCSI_SENSE_KEY(x) (x&0x0F) //!< Sense Key
+
+ /* 4th to 7th bytes - INFORMATION field */
+ uint8_t information[4];
+
+ /* 8th byte - ADDITIONAL SENSE LENGTH field */
+ uint8_t AddSenseLen;
+#define SCSI_SENSE_ADDL_LEN(total_len) ((total_len) - 8)
+
+ /* 9th to 12th byte - COMMAND-SPECIFIC INFORMATION field */
+ uint8_t CmdSpecINFO[4];
+
+ /* 13th byte - ADDITIONAL SENSE CODE field */
+ uint8_t AddSenseCode;
+
+ /* 14th byte - ADDITIONAL SENSE CODE QUALIFIER field */
+ uint8_t AddSnsCodeQlfr;
+
+ /* 15th byte - FIELD REPLACEABLE UNIT CODE field */
+ uint8_t FldReplUnitCode;
+
+ /* 16th byte */
+ uint8_t SenseKeySpec[3];
+#define SCSI_SENSE_SKSV 0x80 //!< Indicates the SENSE-KEY SPECIFIC field contains valid information
+};
+
+COMPILER_PACK_RESET()
+
+/* Vital Product Data page codes */
+enum scsi_vpd_page_code {
+ SCSI_VPD_SUPPORTED_PAGES = 0x00,
+ SCSI_VPD_UNIT_SERIAL_NUMBER = 0x80,
+ SCSI_VPD_DEVICE_IDENTIFICATION = 0x83,
+};
+#define SCSI_VPD_HEADER_SIZE 4
+
+/* Constants associated with the Device Identification VPD page */
+#define SCSI_VPD_ID_HEADER_SIZE 4
+
+#define SCSI_VPD_CODE_SET_BINARY 1
+#define SCSI_VPD_CODE_SET_ASCII 2
+#define SCSI_VPD_CODE_SET_UTF8 3
+
+#define SCSI_VPD_ID_TYPE_T10 1
+
+
+/* Sense keys */
+enum scsi_sense_key {
+ SCSI_SK_NO_SENSE = 0x0,
+ SCSI_SK_RECOVERED_ERROR = 0x1,
+ SCSI_SK_NOT_READY = 0x2,
+ SCSI_SK_MEDIUM_ERROR = 0x3,
+ SCSI_SK_HARDWARE_ERROR = 0x4,
+ SCSI_SK_ILLEGAL_REQUEST = 0x5,
+ SCSI_SK_UNIT_ATTENTION = 0x6,
+ SCSI_SK_DATA_PROTECT = 0x7,
+ SCSI_SK_BLANK_CHECK = 0x8,
+ SCSI_SK_VENDOR_SPECIFIC = 0x9,
+ SCSI_SK_COPY_ABORTED = 0xa,
+ SCSI_SK_ABORTED_COMMAND = 0xb,
+ SCSI_SK_VOLUME_OVERFLOW = 0xd,
+ SCSI_SK_MISCOMPARE = 0xe,
+};
+
+/* Additional Sense Code / Additional Sense Code Qualifier pairs */
+enum scsi_asc_ascq {
+ SCSI_ASC_NO_ADDITIONAL_SENSE_INFO = 0x0000,
+ SCSI_ASC_LU_NOT_READY_REBUILD_IN_PROGRESS = 0x0405,
+ SCSI_ASC_WRITE_ERROR = 0x0c00,
+ SCSI_ASC_UNRECOVERED_READ_ERROR = 0x1100,
+ SCSI_ASC_INVALID_COMMAND_OPERATION_CODE = 0x2000,
+ SCSI_ASC_INVALID_FIELD_IN_CDB = 0x2400,
+ SCSI_ASC_WRITE_PROTECTED = 0x2700,
+ SCSI_ASC_NOT_READY_TO_READY_CHANGE = 0x2800,
+ SCSI_ASC_MEDIUM_NOT_PRESENT = 0x3A00,
+ SCSI_ASC_INTERNAL_TARGET_FAILURE = 0x4400,
+};
+
+/**
+ * \brief SPC-2 Mode parameter
+ * This subclause describes the block descriptors and the pages
+ * used with MODE SELECT and MODE SENSE commands
+ * that are applicable to all SCSI devices.
+ */
+enum scsi_spc_mode {
+ SCSI_MS_MODE_VENDOR_SPEC = 0x00,
+ SCSI_MS_MODE_INFEXP = 0x1C, // Informational exceptions control page
+ SCSI_MS_MODE_ALL = 0x3f,
+};
+
+/**
+ * \brief SPC-2 Informational exceptions control page
+ * See chapter 8.3.8
+ */
+struct spc_control_page_info_execpt {
+ uint8_t page_code;
+ uint8_t page_length;
+#define SPC_MP_INFEXP_PAGE_LENGTH 0x0A
+ uint8_t flags1;
+#define SPC_MP_INFEXP_PERF (1<<7) //!< Initiator Control
+#define SPC_MP_INFEXP_EBF (1<<5) //!< Caching Analysis Permitted
+#define SPC_MP_INFEXP_EWASC (1<<4) //!< Discontinuity
+#define SPC_MP_INFEXP_DEXCPT (1<<3) //!< Size enable
+#define SPC_MP_INFEXP_TEST (1<<2) //!< Writeback Cache Enable
+#define SPC_MP_INFEXP_LOGERR (1<<0) //!< Log errors bit
+ uint8_t mrie;
+#define SPC_MP_INFEXP_MRIE_NO_REPORT 0x00
+#define SPC_MP_INFEXP_MRIE_ASYNC_EVENT 0x01
+#define SPC_MP_INFEXP_MRIE_GEN_UNIT 0x02
+#define SPC_MP_INFEXP_MRIE_COND_RECOV_ERROR 0x03
+#define SPC_MP_INFEXP_MRIE_UNCOND_RECOV_ERROR 0x04
+#define SPC_MP_INFEXP_MRIE_NO_SENSE 0x05
+#define SPC_MP_INFEXP_MRIE_ONLY_REPORT 0x06
+ be32_t interval_timer;
+ be32_t report_count;
+};
+
+
+enum scsi_spc_mode_sense_pc {
+ SCSI_MS_SENSE_PC_CURRENT = 0,
+ SCSI_MS_SENSE_PC_CHANGEABLE = 1,
+ SCSI_MS_SENSE_PC_DEFAULT = 2,
+ SCSI_MS_SENSE_PC_SAVED = 3,
+};
+
+
+
+static inline bool scsi_mode_sense_dbd_is_set(const uint8_t * cdb)
+{
+ return (cdb[1] >> 3) & 1;
+}
+
+static inline uint8_t scsi_mode_sense_get_page_code(const uint8_t * cdb)
+{
+ return cdb[2] & 0x3f;
+}
+
+static inline uint8_t scsi_mode_sense_get_pc(const uint8_t * cdb)
+{
+ return cdb[2] >> 6;
+}
+
+/**
+ * \brief SCSI Mode Parameter Header used by MODE SELECT(6) and MODE
+ * SENSE(6)
+ */
+struct scsi_mode_param_header6 {
+ uint8_t mode_data_length; //!< Number of bytes after this
+ uint8_t medium_type; //!< Medium Type
+ uint8_t device_specific_parameter; //!< Defined by command set
+ uint8_t block_descriptor_length; //!< Length of block descriptors
+};
+
+/**
+ * \brief SCSI Mode Parameter Header used by MODE SELECT(10) and MODE
+ * SENSE(10)
+ */
+struct scsi_mode_param_header10 {
+ be16_t mode_data_length; //!< Number of bytes after this
+ uint8_t medium_type; //!< Medium Type
+ uint8_t device_specific_parameter; //!< Defined by command set
+ uint8_t flags4; //!< LONGLBA in bit 0
+ uint8_t reserved;
+ be16_t block_descriptor_length; //!< Length of block descriptors
+};
+
+/**
+ * \brief SCSI Page_0 Mode Page header (SPF not set)
+ */
+struct scsi_mode_page_0_header {
+ uint8_t page_code;
+#define SCSI_PAGE_CODE_PS (1 << 7) //!< Parameters Saveable
+#define SCSI_PAGE_CODE_SPF (1 << 6) //!< SubPage Format
+ uint8_t page_length; //!< Number of bytes after this
+#define SCSI_MS_PAGE_LEN(total) ((total) - 2)
+};
+
+//@}
+
+#endif // SPC_PROTOCOL_H_
diff --git a/atmel-samd/asf/common/services/usb/class/msc/usb_protocol_msc.h b/atmel-samd/asf/common/services/usb/class/msc/usb_protocol_msc.h
new file mode 100644
index 0000000000..d5312328f2
--- /dev/null
+++ b/atmel-samd/asf/common/services/usb/class/msc/usb_protocol_msc.h
@@ -0,0 +1,147 @@
+/**
+ * \file
+ *
+ * \brief USB Mass Storage Class (MSC) protocol definitions.
+ *
+ * Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * 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
+ * EXPRESSLY AND SPECIFICALLY 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.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Atmel Support
+ */
+
+#ifndef _USB_PROTOCOL_MSC_H_
+#define _USB_PROTOCOL_MSC_H_
+
+
+/**
+ * \ingroup usb_protocol_group
+ * \defgroup usb_msc_protocol USB Mass Storage Class (MSC) protocol definitions
+ *
+ * @{
+ */
+
+/**
+ * \name Possible Class value
+ */
+//@{
+#define MSC_CLASS 0x08
+//@}
+
+/**
+ * \name Possible SubClass value
+ * \note In practise, most devices should use
+ * #MSC_SUBCLASS_TRANSPARENT and specify the actual command set in
+ * the standard INQUIRY data block, even if the MSC spec indicates
+ * otherwise. In particular, RBC is not supported by certain major
+ * operating systems like Windows XP.
+ */
+//@{
+#define MSC_SUBCLASS_RBC 0x01 //!< Reduced Block Commands
+#define MSC_SUBCLASS_ATAPI 0x02 //!< CD/DVD devices
+#define MSC_SUBCLASS_QIC_157 0x03 //!< Tape devices
+#define MSC_SUBCLASS_UFI 0x04 //!< Floppy disk drives
+#define MSC_SUBCLASS_SFF_8070I 0x05 //!< Floppy disk drives
+#define MSC_SUBCLASS_TRANSPARENT 0x06 //!< Determined by INQUIRY
+//@}
+
+/**
+ * \name Possible protocol value
+ * \note Only the BULK protocol should be used in new designs.
+ */
+//@{
+#define MSC_PROTOCOL_CBI 0x00 //!< Command/Bulk/Interrupt
+#define MSC_PROTOCOL_CBI_ALT 0x01 //!< W/o command completion
+#define MSC_PROTOCOL_BULK 0x50 //!< Bulk-only
+//@}
+
+
+/**
+ * \brief MSC USB requests (bRequest)
+ */
+enum usb_reqid_msc {
+ USB_REQ_MSC_BULK_RESET = 0xFF, //!< Mass Storage Reset
+ USB_REQ_MSC_GET_MAX_LUN = 0xFE, //!< Get Max LUN
+};
+
+
+COMPILER_PACK_SET(1)
+
+/**
+ * \name A Command Block Wrapper (CBW).
+ */
+//@{
+struct usb_msc_cbw {
+ le32_t dCBWSignature; //!< Must contain 'USBC'
+ le32_t dCBWTag; //!< Unique command ID
+ le32_t dCBWDataTransferLength; //!< Number of bytes to transfer
+ uint8_t bmCBWFlags; //!< Direction in bit 7
+ uint8_t bCBWLUN; //!< Logical Unit Number
+ uint8_t bCBWCBLength; //!< Number of valid CDB bytes
+ uint8_t CDB[16]; //!< SCSI Command Descriptor Block
+};
+
+#define USB_CBW_SIGNATURE 0x55534243 //!< dCBWSignature value
+#define USB_CBW_DIRECTION_IN (1<<7) //!< Data from device to host
+#define USB_CBW_DIRECTION_OUT (0<<7) //!< Data from host to device
+#define USB_CBW_LUN_MASK 0x0F //!< Valid bits in bCBWLUN
+#define USB_CBW_LEN_MASK 0x1F //!< Valid bits in bCBWCBLength
+//@}
+
+
+/**
+ * \name A Command Status Wrapper (CSW).
+ */
+//@{
+struct usb_msc_csw {
+ le32_t dCSWSignature; //!< Must contain 'USBS'
+ le32_t dCSWTag; //!< Same as dCBWTag
+ le32_t dCSWDataResidue; //!< Number of bytes not transfered
+ uint8_t bCSWStatus; //!< Status code
+};
+
+#define USB_CSW_SIGNATURE 0x55534253 //!< dCSWSignature value
+#define USB_CSW_STATUS_PASS 0x00 //!< Command Passed
+#define USB_CSW_STATUS_FAIL 0x01 //!< Command Failed
+#define USB_CSW_STATUS_PE 0x02 //!< Phase Error
+//@}
+
+COMPILER_PACK_RESET()
+
+//@}
+
+#endif // _USB_PROTOCOL_MSC_H_
diff --git a/atmel-samd/asf/common/services/usb/usb_protocol.h b/atmel-samd/asf/common/services/usb/usb_protocol.h
index 54ebeb4a29..32fafa565b 100644
--- a/atmel-samd/asf/common/services/usb/usb_protocol.h
+++ b/atmel-samd/asf/common/services/usb/usb_protocol.h
@@ -50,6 +50,7 @@
#ifndef _USB_PROTOCOL_H_
#define _USB_PROTOCOL_H_
+#include "compiler.h"
#include "usb_atmel.h"
/**
diff --git a/atmel-samd/asf/sam0/drivers/usb/stack_interface/usb_host_uhd.c b/atmel-samd/asf/sam0/drivers/usb/stack_interface/usb_host_uhd.c
deleted file mode 100644
index 46f57c9096..0000000000
--- a/atmel-samd/asf/sam0/drivers/usb/stack_interface/usb_host_uhd.c
+++ /dev/null
@@ -1,1667 +0,0 @@
-/**
- * \file
- *
- * \brief USB peripheral host wrapper for ASF Stack USB Host Driver (UHD)
- *
- * Copyright (C) 2014-2016 Atmel Corporation. All rights reserved.
- *
- * \asf_license_start
- *
- * \page License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. The name of Atmel may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * 4. This software may only be redistributed and used in connection with an
- * Atmel microcontroller product.
- *
- * 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
- * EXPRESSLY AND SPECIFICALLY 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.
- *
- * \asf_license_stop
- *
- */
-/*
- * Support and FAQ: visit Atmel Support
- */
-
-#include
-#include
-
-/* Get USB host configuration */
-#include "conf_usb_host.h"
-#include "uhd.h"
-#include "usb.h"
-#include "usb_dual.h"
-
-/* Optional UHC callbacks */
-#ifndef UHC_MODE_CHANGE
-# define UHC_MODE_CHANGE(arg)
-#endif
-#ifndef UHC_SOF_EVENT
-# define UHC_SOF_EVENT()
-#endif
-#ifndef UHC_VBUS_CHANGE
-# define UHC_VBUS_CHANGE(b_present)
-#endif
-#ifndef UHC_VBUS_ERROR
-# define UHC_VBUS_ERROR()
-#endif
-
-/**
- * \ingroup usb_host_group
- * \defgroup usb_host_uhd_group USB Host Driver Implement (UHD)
- * USB low-level driver for USB Host mode
- * @{
- */
-
-/* Function declare */
-static void _uhd_ctrl_phase_setup(void);
-static void _uhd_ctrl_phase_data_in_start(void);
-static void _uhd_ctrl_phase_data_in(uint16_t nb_byte_received);
-static void _uhd_ctrl_phase_zlp_in(void);
-static void _uhd_ctrl_phase_data_out(void);
-static void _uhd_ctrl_phase_zlp_out(void);
-static void _uhd_ctrl_request_end(uhd_trans_status_t status);
-static uint8_t _uhd_get_pipe(usb_add_t add, usb_ep_t endp);
-static void _uhd_pipe_trans_complete(struct usb_module *module_inst, void *);
-static void _uhd_ep_abort_pipe(uint8_t pipe, uhd_trans_status_t status);
-static void _uhd_pipe_finish_job(uint8_t pipe, uhd_trans_status_t status);
-
-/* for debug text */
-#ifdef USB_DEBUG
-# define dbg_print printf
-#else
-# define dbg_print(...)
-#endif
-
-/* Maximum size of a transfer in multipacket mode */
-#define UHD_ENDPOINT_MAX_TRANS ((8 *1024 ) - 1)
-
-/* pipe error status */
-#define USB_STATUS_PIPE_DTGLER (1 << 0)
-#define USB_STATUS_PIPE_DAPIDER (1 << 1)
-#define USB_STATUS_PIPE_PIDER (1 << 2)
-#define USB_STATUS_PIPE_TOUTER (1 << 3)
-#define USB_STATUS_PIPE_CRC16ER (1 << 4)
-
-/* Check USB host configuration */
-#ifdef USB_HOST_HS_SUPPORT
-# error The High speed mode is not supported on this part, please remove USB_HOST_HS_SUPPORT in conf_usb_host.h
-#endif
-
-#if (!(SAMD21) && !(SAMR21) && !(SAML21)) && !(SAMDA1) && !(SAMR30)
-# error The current USB Host Driver supports only SAMD21/R21/L21/R30
-#endif
-
-#ifdef USB_HOST_LPM_SUPPORT
-/** Notify that USB Host is enter in suspend LPM state */
-static bool uhd_lpm_suspend = false;
-#endif
-
-/** Store the callback to be called at the end of reset signal */
-static uhd_callback_reset_t uhd_reset_callback = NULL;
-
-/**
- * \name Power management
- *
- * @{
- */
-#ifndef UHD_NO_SLEEP_MGR
-
-#include "sleepmgr.h"
-/** States of USB interface */
-enum uhd_usb_state_enum {
- UHD_STATE_OFF = 0,
- UHD_STATE_WAIT_ID_HOST = 1,
- UHD_STATE_NO_VBUS = 2,
- UHD_STATE_DISCONNECT = 3,
- UHD_STATE_SUSPEND = 4,
- UHD_STATE_SUSPEND_LPM = 5,
- UHD_STATE_IDLE = 6,
-};
-
-enum sleepmgr_mode sleep_mode[] = {
- SLEEPMGR_STANDBY, // UHD_STATE_OFF (not used)
-#if SAML21 || SAMR30
- SLEEPMGR_IDLE, // UHD_STATE_WAIT_ID_HOST
- SLEEPMGR_IDLE, // UHD_STATE_NO_VBUS
- SLEEPMGR_IDLE, // UHD_STATE_DISCONNECT
- SLEEPMGR_IDLE, // UHD_STATE_SUSPEND
- SLEEPMGR_IDLE, // UHD_STATE_SUSPEND_LPM
- SLEEPMGR_IDLE, // UHD_STATE_IDLE
-#else
- SLEEPMGR_IDLE_0, // UHD_STATE_WAIT_ID_HOST
- SLEEPMGR_IDLE_0, // UHD_STATE_NO_VBUS
- SLEEPMGR_IDLE_0, // UHD_STATE_DISCONNECT
- SLEEPMGR_IDLE_2, // UHD_STATE_SUSPEND
- SLEEPMGR_IDLE_2, // UHD_STATE_SUSPEND_LPM
- SLEEPMGR_IDLE_0, // UHD_STATE_IDLE
-#endif
-};
-
-static enum uhd_usb_state_enum uhd_state = UHD_STATE_OFF;
-
-/** \brief Manages the sleep mode following the USB state
- *
- * \param new_state New USB state
- */
-static void uhd_sleep_mode(enum uhd_usb_state_enum new_state)
-{
- if (uhd_state == new_state) {
- return; // No change
- }
- if (new_state != UHD_STATE_OFF) {
- /* Lock new limit */
- sleepmgr_lock_mode(sleep_mode[new_state]);
- }
- if (uhd_state != UHD_STATE_OFF) {
- /* Unlock old limit */
- sleepmgr_unlock_mode(sleep_mode[uhd_state]);
- }
- uhd_state = new_state;
-}
-
-#else
-# define uhd_sleep_mode(arg)
-#endif
-/** @} */
-
-/**
- * \name Control endpoint low level management routine.
- *
- * This function performs control endpoint management.
- * It handles the SETUP/DATA/HANDSHAKE phases of a control transaction.
- *
- * @{
- */
-
-/**
- * \brief Buffer to store the sent/received data on control endpoint
- *
- * Used to avoid a RAM buffer overflow when the payload buffer
- * is smaller than control endpoint size.
- * Also used when payload buffer is not word aligned.
- */
-UHC_BSS(4)
-uint8_t uhd_ctrl_buffer[64];
-
-/**
- * \brief Structure to store the high level setup request
- */
-
-struct uhd_ctrl_request_t{
- /** Buffer to store the setup DATA phase */
- uint8_t *payload;
- /** Callback called when buffer is empty or full */
- uhd_callback_setup_run_t callback_run;
- /** Callback called when request is completed */
- uhd_callback_setup_end_t callback_end;
- /** Next setup request to process */
- struct uhd_ctrl_request_t *next_request;
- /** Setup request definition */
- usb_setup_req_t req;
- /** Size of buffer used in DATA phase */
- uint16_t payload_size;
- /** USB address of control endpoint */
- usb_add_t add;
-};
-
-/** Entry points of setup request list */
-struct uhd_ctrl_request_t *uhd_ctrl_request_first;
-struct uhd_ctrl_request_t *uhd_ctrl_request_last;
-
-/** Remaining time for on-going setup request (No request on-going if equal 0) */
-volatile uint16_t uhd_ctrl_request_timeout;
-
-/** Number of transfered byte on DATA phase of current setup request */
-uint16_t uhd_ctrl_nb_trans;
-
-/** Flag to delay a suspend request after all on-going setup request */
-static bool uhd_b_suspend_requested;
-
-/** Bit definitions to store setup request state machine */
-typedef enum {
- /** Wait a SETUP packet */
- UHD_CTRL_REQ_PHASE_SETUP = 0,
- /** Wait a OUT data packet */
- UHD_CTRL_REQ_PHASE_DATA_OUT = 1,
- /** Wait a IN data packet */
- UHD_CTRL_REQ_PHASE_DATA_IN = 2,
- /** Wait a IN ZLP packet */
- UHD_CTRL_REQ_PHASE_ZLP_IN = 3,
- /** Wait a OUT ZLP packet */
- UHD_CTRL_REQ_PHASE_ZLP_OUT = 4,
-} uhd_ctrl_request_phase_t;
-uhd_ctrl_request_phase_t uhd_ctrl_request_phase;
-
-/** @} */
-
-/**
- * \name Management of bulk/interrupt/isochronous endpoints
- *
- * The UHD manages the data transfer on endpoints:
- * - Start data transfer on endpoint with USB DMA
- * - Send a ZLP packet if requested
- * - Call registered callback to signal end of transfer
- * The transfer abort and stall feature are supported.
- *
- * @{
- */
-
-/** Structure definition to store registered jobs on a pipe */
-typedef struct {
- /** Buffer located in internal RAM to send or fill during job */
- uint8_t *buf;
- /** Internal buffer allocated in internal RAM to receive data in case of small user buffer */
- uint8_t *buf_internal;
- /** Size of buffer to send or fill */
- iram_size_t buf_size;
- /** Total number of transferred data on endpoint */
- iram_size_t nb_trans;
- /** Callback to call at the end of transfer */
- uhd_callback_trans_t call_end;
-
- /** timeout on this request (ms) */
- uint16_t timeout;
-
- /** A job is registered on this pipe */
- uint8_t busy:1;
- /** A short packet is requested for this job on endpoint IN */
- uint8_t b_shortpacket:1;
-} uhd_pipe_job_t;
-
-/** Array to register a job on bulk/interrupt/isochronous endpoint */
-static uhd_pipe_job_t uhd_pipe_job[USB_PIPE_NUM- 1];
-
-/** Variables to manage the suspend/resume sequence */
-static uint8_t uhd_suspend_start;
-static uint8_t uhd_resume_start;
-static uint8_t uhd_pipes_unfreeze;
-
-/** @} */
-
-
-struct usb_module dev;
-
-/**
- * \internal
- * \brief Sends a USB setup packet to start a control request sequence
- */
-static void _uhd_ctrl_phase_setup(void)
-{
- usb_setup_req_t setup_req;
- struct usb_host_pipe_config cfg;
- usb_host_pipe_get_config(&dev, 0, &cfg);
-
- uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_SETUP;
- memcpy( &setup_req, &uhd_ctrl_request_first->req, sizeof(usb_setup_req_t));
- /* Manage LSB/MSB to fit with CPU usage */
- setup_req.wValue = cpu_to_le16(setup_req.wValue);
- setup_req.wIndex = cpu_to_le16(setup_req.wIndex);
- setup_req.wLength = cpu_to_le16(setup_req.wLength);
- uhd_ctrl_nb_trans = 0;
-
- /* Check pipe */
-#ifdef USB_HOST_HUB_SUPPORT
- if (cfg.pipe_type == USB_HOST_PIPE_TYPE_DISABLE) {
- _uhd_ctrl_request_end(UHD_TRANS_DISCONNECT);
- return; // Endpoint not valid
- }
-#error TODO check address in list
- /* Reconfigure USB address of pipe 0 used for all control endpoints */
- uhd_udesc_set_uhaddr(0, uhd_ctrl_request_first->add);
-#else
- if ((cfg.pipe_type == USB_HOST_PIPE_TYPE_DISABLE) ||
- (uhd_ctrl_request_first->add != cfg.device_address)) {
- _uhd_ctrl_request_end(UHD_TRANS_DISCONNECT);
- return; // Endpoint not valid
- }
-#endif
-
- /* Fill pipe */
- memcpy(uhd_ctrl_buffer, &setup_req, sizeof(setup_req));
- uhd_ctrl_request_timeout = 5000;
-
- /* Start transfer */
- usb_host_pipe_setup_job(&dev, 0, uhd_ctrl_buffer);
- usb_host_pipe_enable_callback(&dev, 0, USB_HOST_PIPE_CALLBACK_SETUP);
-}
-
-/**
- * \internal
- * \brief Starts the DATA IN phase on control endpoint
- */
-static void _uhd_ctrl_phase_data_in_start(void)
-{
- struct usb_host_pipe_config cfg;
- usb_host_pipe_get_config(&dev, 0, &cfg);
-
- uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_DATA_IN;
-
- usb_host_pipe_read_job(&dev, 0, uhd_ctrl_buffer, cfg.size);
-}
-
-/**
- * \internal
- * \brief Manages the DATA IN phase on control endpoint
- *
- * \param nb_byte_received Number of bytes received
- */
-static void _uhd_ctrl_phase_data_in(uint16_t nb_byte_received)
-{
- bool b_short_packet;
- uint8_t *ptr_ep_data;
-
- struct usb_host_pipe_config cfg;
- usb_host_pipe_get_config(&dev, 0, &cfg);
-
- /** In HUB mode, the control pipe is always configured to 64B */
- /** thus the short packet flag must be computed */
- b_short_packet = (nb_byte_received != cfg.size);
-
- ptr_ep_data = uhd_ctrl_buffer;
-uhd_ctrl_receiv_in_read_data:
- /* Copy data from pipe to payload buffer */
- while (uhd_ctrl_request_first->payload_size && nb_byte_received) {
- *uhd_ctrl_request_first->payload++ = *ptr_ep_data++;
- uhd_ctrl_nb_trans++;
- uhd_ctrl_request_first->payload_size--;
- nb_byte_received--;
- }
-
- if (!uhd_ctrl_request_first->payload_size && nb_byte_received) {
- /* payload buffer is full to store data remaining */
- if (uhd_ctrl_request_first->callback_run == NULL
- || !uhd_ctrl_request_first->callback_run(
- cfg.device_address,
- &uhd_ctrl_request_first->payload,
- &uhd_ctrl_request_first->payload_size)) {
- /* DATA phase aborted by host */
- goto uhd_ctrl_phase_data_in_end;
- }
- /*
- * The payload buffer has been updated by the callback
- * thus the data load can restart.
- */
- goto uhd_ctrl_receiv_in_read_data;
- }
-
- /* Test short packet */
- if ((uhd_ctrl_nb_trans == uhd_ctrl_request_first->req.wLength)
- || b_short_packet) {
- /* End of DATA phase or DATA phase abort from device */
-uhd_ctrl_phase_data_in_end:
- _uhd_ctrl_phase_zlp_out();
- return;
- }
-
- usb_host_pipe_read_job(&dev, 0, uhd_ctrl_buffer, cfg.size);
-}
-
-/**
- * \internal
- * \brief Starts the ZLP IN phase on control endpoint
- */
-static void _uhd_ctrl_phase_zlp_in(void)
-{
- uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_ZLP_IN;
-
- usb_host_pipe_set_toggle(&dev, 0);
-
- usb_host_pipe_read_job(&dev, 0, uhd_ctrl_buffer, 0);
-}
-
-/**
- * \internal
- * \brief Manages the DATA OUT phase on control endpoint
- */
-static void _uhd_ctrl_phase_data_out(void)
-{
- struct usb_host_pipe_config cfg;
- usb_host_pipe_get_config(&dev, 0, &cfg);
-
- uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_DATA_OUT;
- uint16_t nb_trans;
-
- if (uhd_ctrl_nb_trans == uhd_ctrl_request_first->req.wLength) {
- /* End of DATA phase */
- _uhd_ctrl_phase_zlp_in();
- return;
- }
-
- if (!uhd_ctrl_request_first->payload_size) {
- /* Buffer empty, then request a new buffer */
- if (uhd_ctrl_request_first->callback_run==NULL
- || !uhd_ctrl_request_first->callback_run(
- cfg.device_address,
- &uhd_ctrl_request_first->payload,
- &uhd_ctrl_request_first->payload_size)) {
- /* DATA phase aborted by host */
- _uhd_ctrl_phase_zlp_in();
- return;
- }
- }
-
- nb_trans = uhd_ctrl_request_first->payload_size;
- if (nb_trans > cfg.size) {
- nb_trans = cfg.size;
- }
-
- /* Link the user buffer directly on USB hardware DMA */
- memcpy(uhd_ctrl_buffer, uhd_ctrl_request_first->payload, nb_trans);
-
- /* Update counters */
- uhd_ctrl_request_first->payload += nb_trans;
- uhd_ctrl_nb_trans += nb_trans;
- uhd_ctrl_request_first->payload_size -= nb_trans;
-
- /* Start transfer */
- usb_host_pipe_write_job(&dev, 0, uhd_ctrl_buffer, nb_trans);
-}
-
-/**
- * \internal
- * \brief Starts the ZLP OUT phase on control endpoint
- */
-static void _uhd_ctrl_phase_zlp_out(void)
-{
- uhd_ctrl_request_phase = UHD_CTRL_REQ_PHASE_ZLP_OUT;
-
- usb_host_pipe_set_toggle(&dev, 0);
-
- /* No need to link a user buffer directly on USB hardware DMA */
- /* Start transfer */
- usb_host_pipe_write_job(&dev, 0, uhd_ctrl_buffer, 0);
-}
-
-/**
- * \internal
- * \brief Call the callback linked to control request and start the next request
- *
- * \param status Request finish status passed to callback
- */
-static void _uhd_ctrl_request_end(uhd_trans_status_t status)
-{
- irqflags_t flags;
- uhd_callback_setup_end_t callback_end;
- struct uhd_ctrl_request_t *request_to_free;
- bool b_new_request;
-
- struct usb_host_pipe_config cfg;
- usb_host_pipe_get_config(&dev, 0, &cfg);
-
- Assert (uhd_ctrl_request_first != NULL);
-
- uhd_ctrl_request_timeout = 0;
-
- /* Remove request from the control request list */
- callback_end = uhd_ctrl_request_first->callback_end;
- request_to_free = uhd_ctrl_request_first;
- flags = cpu_irq_save();
- uhd_ctrl_request_first = uhd_ctrl_request_first->next_request;
- b_new_request = (uhd_ctrl_request_first != NULL);
- cpu_irq_restore(flags);
- free(request_to_free);
-
- /* Call callback */
- if (callback_end != NULL) {
- callback_end(cfg.device_address, status, uhd_ctrl_nb_trans);
- }
-
- /* If a setup request is pending and no started by previous callback */
- if (b_new_request) {
- _uhd_ctrl_phase_setup();
- }
- if (uhd_b_suspend_requested) {
- /* A suspend request has been delay after all setup request */
- uhd_b_suspend_requested = false;
- uhd_suspend();
- }
-}
-
-/**
- * \internal
- * \brief Manages timeouts and actions based on SOF events
- * - Suspend delay
- * - Resume delay
- * - Setup packet delay
- * - Timeout on endpoint control transfer
- * - Timeouts on bulk/interrupt/isochronous endpoint transfers
- * - UHC user notification
- * - SOF user notification
- *
- * \param module_inst Pointer to USB module instance
- */
-static void _uhd_sof_interrupt(struct usb_module *module_inst)
-{
- /* Manage a delay to enter in suspend */
- if (uhd_suspend_start) {
- if (--uhd_suspend_start == 0) {
- /* In case of high CPU frequency,
- * the current Keep-Alive/SOF can be always on-going
- * then wait end of SOF generation
- * to be sure that disable SOF has been accepted
- */
- dbg_print("SUSP\n");
- usb_host_disable_sof(&dev);
- /* Enable wakeup/resumes interrupts */
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_WAKEUP);
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_DNRSM);
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_UPRSM);
-
- /* Check that the hardware state machine has left the IDLE/Active mode
- * before freeze USB clock
- */
- while (2==usb_get_state_machine_status(&dev));
- uhd_sleep_mode(UHD_STATE_SUSPEND);
- }
- return; // Abort SOF events
- }
- /* Manage a delay to exit of suspend */
- if (uhd_resume_start) {
- if (--uhd_resume_start == 0) {
- /* Restore pipes unfrozen */
- for (uint8_t pipe = 1; pipe < USB_PIPE_NUM; pipe++) {
- if ((uhd_pipes_unfreeze >> pipe) & 0x01) {
- usb_host_pipe_unfreeze(&dev, pipe);
- }
- }
- uhc_notify_resume();
- }
- return; // Abort SOF events
- }
- /* Manage the timeout on endpoint control transfer */
- if (uhd_ctrl_request_timeout) {
- /* Setup request on-going */
- if (--uhd_ctrl_request_timeout == 0) {
- /* Stop request */
- usb_host_pipe_freeze(&dev, 0);
- _uhd_ctrl_request_end(UHD_TRANS_TIMEOUT);
- }
- }
- /* Manage the timeouts on endpoint transfer */
- uhd_pipe_job_t *ptr_job;
- for (uint8_t pipe = 1; pipe < USB_PIPE_NUM; pipe++) {
- ptr_job = &uhd_pipe_job[pipe - 1];
- if (ptr_job->busy == true) {
- if (ptr_job->timeout) {
- /* Timeout enabled on this job */
- if (--ptr_job->timeout == 0) {
- /* Abort job */
- _uhd_ep_abort_pipe(pipe,UHD_TRANS_TIMEOUT);
- }
- }
- }
- }
-
- /* Notify the UHC */
- uhc_notify_sof(false);
-
- /* Notify the user application */
- UHC_SOF_EVENT();
-}
-
-/**
- * \internal
- * \brief Manages bus reset interrupt
- *
- * \param module_inst Pointer to USB module instance
- */
-static void _uhd_reset(struct usb_module *module_inst)
-{
- if (uhd_reset_callback != NULL) {
- uhd_reset_callback();
- }
-}
-
-/**
- * \internal
- * \brief Manages wakeup interrupt
- *
- * \param module_inst Pointer to USB module instance
- */
-static void _uhd_wakeup(struct usb_module *module_inst)
-{
- /* Here the wakeup interrupt has been used to detect:
- * - connection with an asynchronous interrupt
- * - down/upstream resume with an asynchronous interrupt
- */
- dbg_print("WAKEUP\n");
-#ifdef USB_HOST_LPM_SUPPORT
- if (uhd_lpm_suspend) {
- usb_host_send_l1_resume(&dev);
- uhd_lpm_suspend = false;
- uhc_notify_resume_lpm();
- } else
-#endif
- {
- usb_host_send_resume(&dev);
- /* Wait 50ms before restarting transfer */
- uhd_resume_start = 50;
- }
- /* Disable wakeup/resumes interrupts */
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_WAKEUP);
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_DNRSM);
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_UPRSM);
- uhd_sleep_mode(UHD_STATE_IDLE);
-}
-
-/**
- * \internal
- * \brief Manages downstream resume interrupt
- *
- * \param module_inst Pointer to USB module instance
- */
-static void _uhd_downstream_resume(struct usb_module *module_inst)
-{
- dbg_print("DOWN RES\n");
- /* Disable wakeup/resumes interrupts */
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_WAKEUP);
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_DNRSM);
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_UPRSM);
-#ifdef USB_HOST_LPM_SUPPORT
- if (uhd_lpm_suspend) {
- uhd_lpm_suspend = false;
- uhc_notify_resume_lpm();
- } else
-#endif
- {
- /* Wait 50ms before restarting transfer */
- uhd_resume_start = 50;
- }
- uhd_sleep_mode(UHD_STATE_IDLE);
-}
-
-/**
- * \internal
- * \brief Manages upstream resume interrupt
- *
- * \param module_inst Pointer to USB module instance
- */
-static void _uhd_upstream_resume(struct usb_module *module_inst)
-{
- dbg_print("UP RES\n");
-#ifdef USB_HOST_LPM_SUPPORT
- if (uhd_lpm_suspend) {
- usb_host_send_l1_resume(&dev);
- uhd_lpm_suspend = false;
- uhc_notify_resume_lpm();
- } else
-#endif
- {
- usb_host_send_resume(&dev);
- /* Wait 50ms before restarting transfer */
- uhd_resume_start = 50;
- }
- /* Disable wakeup/resumes interrupts */
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_WAKEUP);
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_DNRSM);
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_UPRSM);
- uhd_sleep_mode(UHD_STATE_IDLE);
-}
-
-/**
- * \internal
- * \brief Manages ram access error interrupt
- *
- * \param module_inst Pointer to USB module instance
- */
-static void _uhd_ram_error(struct usb_module *module_inst)
-{
-#ifdef UHC_RAM_ACCESS_ERR_EVENT
- UHC_RAM_ACCESS_ERR_EVENT();
-#endif
- dbg_print("!!!! RAM ERR !!!!\n");
-}
-
-/**
- * \internal
- * \brief Manages connection interrupt
- *
- * \param module_inst Pointer to USB module instance
- */
-static void _uhd_connect(struct usb_module *module_inst)
-{
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_CONNECT);
- dbg_print("CONN\n");
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_DISCONNECT);
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_WAKEUP);
- usb_host_enable_sof(&dev);
- uhd_sleep_mode(UHD_STATE_IDLE);
- uhd_suspend_start = 0;
- uhd_resume_start = 0;
- uhc_notify_connection(true);
-}
-
-/**
- * \internal
- * \brief Manages disconnection interrupt
- *
- * \param module_inst Pointer to USB module instance
- */
-static void _uhd_disconnect(struct usb_module *module_inst)
-{
- /* This should be the normal way to handle this event. */
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_DISCONNECT);
- dbg_print("DISC\n");
- /* Disable wakeup/resumes interrupts,
- * in case of disconnection during suspend mode
- */
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_WAKEUP);
- /* Enable asynchronous wakeup interrupt to allow a CPU wakeup
- * when a connection occurs.
- */
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_CONNECT);
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_WAKEUP);
- uhd_suspend_start = 0;
- uhd_resume_start = 0;
- uhd_sleep_mode(UHD_STATE_DISCONNECT);
- uhc_notify_connection(false);
-}
-
-#if USB_VBUS_EIC
-/**
- * \name USB VBUS PAD management
- *
- * @{
- */
-
- /** Check if USB VBus is available */
-# define is_usb_vbus_high() port_pin_get_input_level(USB_VBUS_PIN)
-
-/**
- * USB VBUS pin change handler
- */
-static void _uhd_vbus_handler(void)
-{
- extint_chan_disable_callback(USB_VBUS_EIC_LINE,
- EXTINT_CALLBACK_TYPE_DETECT);
- if (is_usb_vbus_high()) {
- UHC_VBUS_CHANGE(true);
- }
- if (!is_usb_vbus_high()) {
- uhd_sleep_mode(UHD_STATE_NO_VBUS);
- UHC_VBUS_CHANGE(false);
- }
- extint_chan_enable_callback(USB_VBUS_EIC_LINE,
- EXTINT_CALLBACK_TYPE_DETECT);
-}
-
-/**
- * USB VBUS pin config
- */
-static void _usb_vbus_config(void)
-{
- struct port_config pin_conf;
- port_get_config_defaults(&pin_conf);
-
- /* Set USB VBUS Pin as inputs */
- pin_conf.direction = PORT_PIN_DIR_INPUT;
- pin_conf.input_pull = PORT_PIN_PULL_UP;
- port_pin_set_config(USB_VBUS_PIN, &pin_conf);
-
- /* Initialize EIC for vbus checking */
- struct extint_chan_conf eint_chan_conf;
- extint_chan_get_config_defaults(&eint_chan_conf);
-
- eint_chan_conf.gpio_pin = USB_VBUS_PIN;
- eint_chan_conf.gpio_pin_mux = USB_VBUS_EIC_MUX;
- eint_chan_conf.detection_criteria = EXTINT_DETECT_LOW;
- eint_chan_conf.filter_input_signal = true;
-
- extint_chan_disable_callback(USB_VBUS_EIC_LINE,
- EXTINT_CALLBACK_TYPE_DETECT);
- extint_chan_set_config(USB_VBUS_EIC_LINE, &eint_chan_conf);
- extint_register_callback(_uhd_vbus_handler,
- USB_VBUS_EIC_LINE,
- EXTINT_CALLBACK_TYPE_DETECT);
- extint_chan_enable_callback(USB_VBUS_EIC_LINE,
- EXTINT_CALLBACK_TYPE_DETECT);
-}
-/** @} */
-#endif
-
-void uhd_enable(void)
-{
- irqflags_t flags;
-
- /* To avoid USB interrupt before end of initialization */
- flags = cpu_irq_save();
-
-#if USB_ID_EIC
- if (usb_dual_enable()) {
- /* The current mode has been started by otg_dual_enable() */
- cpu_irq_restore(flags);
- return;
- }
-#endif
- uhd_ctrl_request_first = NULL;
- uhd_ctrl_request_last = NULL;
- uhd_ctrl_request_timeout = 0;
- uhd_suspend_start = 0;
- uhd_resume_start = 0;
- uhd_b_suspend_requested = false;
-
- struct usb_config cfg;
- usb_get_config_defaults(&cfg);
- cfg.select_host_mode = 1;
- usb_init(&dev,USB, &cfg);
- usb_enable(&dev);
-
- uhd_sleep_mode(UHD_STATE_NO_VBUS);
-
-#if USB_VBUS_EIC
- _usb_vbus_config();
- if (is_usb_vbus_high()) {
- /* Force Vbus interrupt when Vbus is always high */
- _uhd_vbus_handler();
- usb_host_enable(&dev);
- uhd_sleep_mode(UHD_STATE_DISCONNECT);
- } else {
- dbg_print("VBUS low, there is some power issue on board!!! \n");
- }
-#else
- usb_host_enable(&dev);
-#endif
-
- usb_host_register_callback(&dev, USB_HOST_CALLBACK_SOF, _uhd_sof_interrupt);
- usb_host_register_callback(&dev, USB_HOST_CALLBACK_RESET, _uhd_reset);
- usb_host_register_callback(&dev, USB_HOST_CALLBACK_WAKEUP, _uhd_wakeup);
- usb_host_register_callback(&dev, USB_HOST_CALLBACK_DNRSM, _uhd_downstream_resume);
- usb_host_register_callback(&dev, USB_HOST_CALLBACK_UPRSM, _uhd_upstream_resume);
- usb_host_register_callback(&dev, USB_HOST_CALLBACK_RAMACER, _uhd_ram_error);
- usb_host_register_callback(&dev, USB_HOST_CALLBACK_CONNECT, _uhd_connect);
- usb_host_register_callback(&dev, USB_HOST_CALLBACK_DISCONNECT, _uhd_disconnect);
-
- /* Enable main control interrupt */
- /* Connection, SOF and reset */
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_SOF);
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_RESET);
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_RAMACER);
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_CONNECT);
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_DISCONNECT);
-
- cpu_irq_restore(flags);
-}
-
-void uhd_disable(bool b_id_stop)
-{
- irqflags_t flags;
- UNUSED(b_id_stop);
-
- /* Disable Vbus change interrupts */
-#if USB_VBUS_EIC
- extint_chan_disable_callback(USB_VBUS_EIC_LINE,
- EXTINT_CALLBACK_TYPE_DETECT);
-#endif
-
- /* Disable main control interrupts */
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_SOF);
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_RESET);
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_RAMACER);
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_CONNECT);
- usb_host_disable_callback(&dev, USB_HOST_CALLBACK_DISCONNECT);
- usb_host_disable_sof(&dev);
- uhc_notify_connection(false);
-
-#if USB_ID_EIC
- uhd_sleep_mode(UHD_STATE_WAIT_ID_HOST);
- if (!b_id_stop) {
- return; // No need to disable host, it is done automatically by hardware
- }
-#endif
-
- flags = cpu_irq_save();
- usb_dual_disable();
- cpu_irq_restore(flags);
-}
-
-uhd_speed_t uhd_get_speed(void)
-{
- switch (usb_host_get_speed(&dev)) {
- case USB_SPEED_LOW:
- return UHD_SPEED_LOW;
- case USB_SPEED_FULL:
- return UHD_SPEED_FULL;
- default:
- Assert(false);
- return UHD_SPEED_LOW;
- }
-}
-
-uint16_t uhd_get_frame_number(void)
-{
- return usb_host_get_frame_number(&dev);
-}
-
-uint16_t uhd_get_microframe_number(void)
-{
- /* nothing to do */
- return 0;
-}
-
-void uhd_send_reset(uhd_callback_reset_t callback)
-{
- uhd_reset_callback = callback;
- usb_host_send_reset(&dev);
-}
-
-void uhd_suspend(void)
-{
- if (uhd_ctrl_request_timeout) {
- /* Delay suspend after setup requests */
- uhd_b_suspend_requested = true;
- return;
- }
- /* Save pipe freeze states and freeze pipes */
- uhd_pipes_unfreeze = 0;
- for (uint8_t pipe = 1; pipe < USB_PIPE_NUM; pipe++) {
- uhd_pipes_unfreeze |= (!usb_host_pipe_is_frozen(&dev, pipe)) << pipe;
- usb_host_pipe_freeze(&dev, pipe);
- }
- /* Wait three SOFs before entering in suspend state */
- uhd_suspend_start = 3;
-}
-
-bool uhd_is_suspend(void)
-{
- return !usb_host_is_sof_enabled(&dev);
-}
-
-void uhd_resume(void)
-{
- if (usb_host_is_sof_enabled(&dev)) {
- /* Currently in IDLE mode (!=Suspend) */
- if (uhd_suspend_start) {
- /* Suspend mode on going
- * then stop it and start resume event
- */
- uhd_suspend_start = 0;
- uhd_resume_start = 1;
- }
- return;
- }
-
-#ifdef USB_HOST_LPM_SUPPORT
- struct usb_host_pipe_config cfg;
- usb_host_pipe_get_config(&dev, 0, &cfg);
-
- if (cfg.pipe_type == USB_HOST_PIPE_TYPE_EXTENDED) {
- /* LPM Suspend command is on going, then ignore resume */
- return;
- }
-
- if (uhd_lpm_suspend) {
- dbg_print("SEND_RESUME_L1\n");
- usb_host_send_l1_resume(&dev);
- } else
-#endif
- {
- dbg_print("SEND_RESUME\n");
- usb_host_send_resume(&dev);
- }
- uhd_sleep_mode(UHD_STATE_IDLE);
-}
-
-#ifdef USB_HOST_LPM_SUPPORT
-bool uhd_suspend_lpm(bool b_remotewakeup, uint8_t hird)
-{
- if (uhd_ctrl_request_timeout) {
- return false;
- }
- /* Do not freeze pipe to restart its immediatly after resume */
- dbg_print("EXT_LPM\n");
-
- /* Set the LPM job */
- usb_host_pipe_lpm_job(&dev, 0, b_remotewakeup, hird);
-
- /* Wait LPM ACK through interrupt */
- return true;
-}
-#endif
-
-bool uhd_setup_request(
- usb_add_t add,
- usb_setup_req_t *req,
- uint8_t *payload,
- uint16_t payload_size,
- uhd_callback_setup_run_t callback_run,
- uhd_callback_setup_end_t callback_end)
-{
- irqflags_t flags;
- struct uhd_ctrl_request_t *request;
- bool b_start_request = false;
-
- request = malloc(sizeof(struct uhd_ctrl_request_t));
- if (request == NULL) {
- Assert(false);
- return false;
- }
-
- /* Fill structure */
- request->add = (uint8_t) add;
- memcpy(&request->req, req, sizeof(usb_setup_req_t));
- request->payload = payload;
- request->payload_size = payload_size;
- request->callback_run = callback_run;
- request->callback_end = callback_end;
- request->next_request = NULL;
-
- /* Add this request in the queue */
- flags = cpu_irq_save();
- if (uhd_ctrl_request_first == NULL) {
- uhd_ctrl_request_first = request;
- b_start_request = true;
- } else {
- uhd_ctrl_request_last->next_request = request;
- }
- uhd_ctrl_request_last = request;
- cpu_irq_restore(flags);
-
- if (b_start_request) {
- /* Start immediately request */
- _uhd_ctrl_phase_setup();
- }
- return true;
-}
-
-/**
- * \internal
- * \brief Manages endpoint 0 transfer complete interrupt
- *
- * \param module_inst Pointer to USB module instance
- * \param pointer Pointer to USB pipe transfer callback status parameters
- */
-static void _uhd_ep0_transfer_complete(struct usb_module *module_inst, void *pointer)
-{
- struct usb_pipe_callback_parameter *p_callback_para;
- p_callback_para = (struct usb_pipe_callback_parameter *)pointer;
-
- struct usb_host_pipe_config cfg;
- usb_host_pipe_get_config(&dev, 0, &cfg);
-
-#ifdef USB_HOST_LPM_SUPPORT
- if (cfg.pipe_type == USB_HOST_PIPE_TYPE_EXTENDED) {
- dbg_print("EXT_LPM_ACK\n");
- cfg.pipe_type = USB_HOST_PIPE_TYPE_CONTROL;
- usb_host_pipe_set_config(&dev, 0, &cfg);
- /* Enable wakeup/resumes interrupts */
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_WAKEUP);
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_DNRSM);
- usb_host_enable_callback(&dev, USB_HOST_CALLBACK_UPRSM);
- uhd_lpm_suspend = true;
- uhd_sleep_mode(UHD_STATE_SUSPEND_LPM);
- return;
- }
-#endif
-
- usb_host_pipe_freeze(&dev, 0);
- switch(uhd_ctrl_request_phase) {
- case UHD_CTRL_REQ_PHASE_DATA_IN:
- _uhd_ctrl_phase_data_in(p_callback_para->transfered_size);
- break;
- case UHD_CTRL_REQ_PHASE_ZLP_IN:
- _uhd_ctrl_request_end(UHD_TRANS_NOERROR);
- break;
- case UHD_CTRL_REQ_PHASE_DATA_OUT:
- _uhd_ctrl_phase_data_out();
- break;
- case UHD_CTRL_REQ_PHASE_ZLP_OUT:
- _uhd_ctrl_request_end(UHD_TRANS_NOERROR);
- break;
- default:
- Assert(false);
- break;
- }
-}
-
-/**
- * \internal
- * \brief Manages endpoint 0 error interrupt
- *
- * \param module_inst Pointer to USB module instance
- * \param pointer Pointer to USB pipe transfer callback status parameters
- */
-static void _uhd_ep0_error(struct usb_module *module_inst, void *pointer)
-{
-#ifdef USB_HOST_LPM_SUPPORT
- struct usb_host_pipe_config cfg;
- usb_host_pipe_get_config(&dev, 0, &cfg);
-
- if (cfg.pipe_type == USB_HOST_PIPE_TYPE_EXTENDED) {
- dbg_print("EXT_LPM_ERROR\n");
- cfg.pipe_type = USB_HOST_PIPE_TYPE_CONTROL;
- usb_host_pipe_set_config(&dev, 0, &cfg);
- return;
- }
-#endif
-
- dbg_print("CTRL Error\n");
- struct usb_pipe_callback_parameter *p_callback_para;
- p_callback_para = (struct usb_pipe_callback_parameter *)pointer;
-
- uhd_trans_status_t uhd_error;
-
- /* Get and ack error */
- switch(p_callback_para->pipe_error_status) {
- case USB_STATUS_PIPE_DTGLER:
- uhd_error = UHD_TRANS_DT_MISMATCH;
- break;
- case USB_STATUS_PIPE_TOUTER:
- uhd_error = UHD_TRANS_NOTRESPONDING;
- break;
- case USB_STATUS_PIPE_CRC16ER:
- uhd_error = UHD_TRANS_CRC;
- break;
- case USB_STATUS_PIPE_DAPIDER:
- case USB_STATUS_PIPE_PIDER:
- uhd_error = UHD_TRANS_PIDFAILURE;
- break;
- default:
- uhd_error = UHD_TRANS_TIMEOUT;
- break;
- }
-
- /* Get and ack error */
- _uhd_ctrl_request_end(uhd_error);
-}
-
-/**
- * \internal
- * \brief Manages endpoint 0 setup interrupt
- *
- * \param module_inst Pointer to USB module instance
- * \param null Not used
- */
-static void _uhd_ep0_setup(struct usb_module *module_inst, void *null)
-{
- /* SETUP packet sent */
- usb_host_pipe_freeze(&dev, 0);
- dbg_print("CTRL Setup\n");
- Assert(uhd_ctrl_request_phase == UHD_CTRL_REQ_PHASE_SETUP);
-
- /* Start DATA phase */
- if ((uhd_ctrl_request_first->req.bmRequestType & USB_REQ_DIR_MASK)
- == USB_REQ_DIR_IN ) {
- _uhd_ctrl_phase_data_in_start();
- } else {
- if (uhd_ctrl_request_first->req.wLength) {
- _uhd_ctrl_phase_data_out();
- } else {
- /* No DATA phase */
- _uhd_ctrl_phase_zlp_in();
- }
- }
-}
-
-/**
- * \internal
- * \brief Manages endpoint 0 stall interrupt
- *
- * \param module_inst Pointer to USB module instance
- * \param null Not used
- */
-static void _uhd_ep0_stall(struct usb_module *module_inst, void *null)
-{
-#ifdef USB_HOST_LPM_SUPPORT
- struct usb_host_pipe_config cfg;
- usb_host_pipe_get_config(&dev, 0, &cfg);
-
- if (cfg.pipe_type == USB_HOST_PIPE_TYPE_EXTENDED) {
- dbg_print("EXT_LPM_STALL\n");
- cfg.pipe_type = USB_HOST_PIPE_TYPE_CONTROL;
- usb_host_pipe_set_config(&dev, 0, &cfg);
- return;
- }
-#endif
-
- dbg_print("CTRL Stall\n");
- /* Stall Handshake received */
- _uhd_ctrl_request_end(UHD_TRANS_STALL);
-}
-
-
-/**
- * \internal
- * \brief Returns the pipe number matching a USB endpoint
- *
- * \param add USB device address
- * \param endp Endpoint Address
- *
- * \return Pipe number
- */
-static uint8_t _uhd_get_pipe(usb_add_t add, usb_ep_t endp)
-{
- struct usb_host_pipe_config cfg;
- uint8_t usb_pipe = 1;
- for (;usb_pipe < USB_PIPE_NUM;usb_pipe ++) {
- usb_host_pipe_get_config(&dev, usb_pipe, &cfg);
- if ((add == cfg.device_address) && (endp == cfg.endpoint_address)) {
- return usb_pipe;
- }
- }
- return 0;
-}
-
-/**
- * \internal
- * \brief Computes and starts the next transfer on a pipe
- *
- * \param module_inst Pointer to USB module instance
- * \param pointer Pointer to USB pipe transfer callback status parameters
- */
-static void _uhd_pipe_trans_complete(struct usb_module *module_inst, void *pointer)
-{
- struct usb_pipe_callback_parameter *p_callback_para;
- p_callback_para = (struct usb_pipe_callback_parameter *)pointer;
-
- struct usb_host_pipe_config cfg;
- usb_host_pipe_get_config(&dev, p_callback_para->pipe_num, &cfg);
-
- uhd_pipe_job_t *ptr_job;
- uint16_t pipe_size, nb_trans;
- uint16_t max_trans;
- iram_size_t next_trans;
- irqflags_t flags;
-
- pipe_size = cfg.size;
-
- /* Get job corresponding at endpoint */
- ptr_job = &uhd_pipe_job[p_callback_para->pipe_num - 1];
-
- if (!ptr_job->busy) {
- return; // No job is running, then ignore it (system error)
- }
-
- if (!(cfg.endpoint_address & USB_EP_DIR_IN)) {
- usb_host_pipe_freeze(&dev, p_callback_para->pipe_num);
- /* Transfer complete on OUT */
- nb_trans = p_callback_para->transfered_size;
-
- /* Update number of transferred data */
- ptr_job->nb_trans += nb_trans;
-
- /* Need to send other data */
- if ((ptr_job->nb_trans != ptr_job->buf_size)
- || ptr_job->b_shortpacket) {
- next_trans = ptr_job->buf_size - ptr_job->nb_trans;
- if (UHD_ENDPOINT_MAX_TRANS < next_trans) {
- /**
- * The USB hardware supports a maximum
- * transfer size of UHD_ENDPOINT_MAX_TRANS Bytes
- */
- next_trans = UHD_ENDPOINT_MAX_TRANS -
- (UHD_ENDPOINT_MAX_TRANS % pipe_size);
- usb_host_pipe_set_auto_zlp(&dev, p_callback_para->pipe_num, false);
- } else {
- /* Need ZLP, if requested and last packet is not a short packet */
- usb_host_pipe_set_auto_zlp(&dev, p_callback_para->pipe_num, ptr_job->b_shortpacket);
- ptr_job->b_shortpacket = false; // No need to request another ZLP
- }
- usb_host_pipe_write_job(&dev, p_callback_para->pipe_num, &ptr_job->buf[ptr_job->nb_trans], next_trans);
-
- /* Enable interrupt */
- flags = cpu_irq_save();
- usb_host_pipe_enable_callback(&dev,p_callback_para->pipe_num,USB_HOST_PIPE_CALLBACK_TRANSFER_COMPLETE);
- cpu_irq_restore(flags);
- return;
- }
- } else {
- /* Transfer complete on IN */
- nb_trans = p_callback_para->transfered_size;
-
- /* May be required to copy received data from cache buffer to user buffer */
- if (ptr_job->buf_internal != NULL) {
- memcpy(&ptr_job->buf[ptr_job->nb_trans],
- ptr_job->buf_internal,
- ptr_job->buf_size % pipe_size);
- free(ptr_job->buf_internal);
- ptr_job->buf_internal = NULL;
- }
-
- /* Update number of transfered data */
- ptr_job->nb_trans += nb_trans;
- if (ptr_job->nb_trans > ptr_job->buf_size) {
- ptr_job->nb_trans = ptr_job->buf_size;
- }
-
- /**
- * If all previous requested data have been received and user buffer not full
- * then need to receive other data
- */
- if ((nb_trans == p_callback_para->required_size)
- && (ptr_job->nb_trans != ptr_job->buf_size)) {
- next_trans = ptr_job->buf_size - ptr_job->nb_trans;
- max_trans = UHD_ENDPOINT_MAX_TRANS;
- /* 256 is the maximum of IN requests via UPINRQ */
- if ((256L * pipe_size) < UHD_ENDPOINT_MAX_TRANS) {
- max_trans = 256L * pipe_size;
- }
- if (max_trans < next_trans) {
- /* The USB hardware support a maximum transfer size
- * of UHD_ENDPOINT_MAX_TRANS Bytes
- */
- next_trans = max_trans;
- }
-
- if (next_trans < pipe_size) {
- /* Use the cache buffer for Bulk or Interrupt size endpoint */
- ptr_job->buf_internal = malloc(pipe_size);
- if (ptr_job->buf_internal == NULL) {
- Assert(ptr_job->buf_internal != NULL);
- goto uhd_pipe_trans_complet_end;
- }
- usb_host_pipe_read_job(&dev, p_callback_para->pipe_num, ptr_job->buf_internal, pipe_size);
- } else {
- next_trans -= next_trans % pipe_size;
- /* Link the user buffer directly on USB hardware DMA */
- usb_host_pipe_read_job(&dev, p_callback_para->pipe_num, &ptr_job->buf[ptr_job->nb_trans], next_trans);
- }
- /* Enable interrupt */
- flags = cpu_irq_save();
- usb_host_pipe_enable_callback(&dev,p_callback_para->pipe_num,USB_HOST_PIPE_CALLBACK_TRANSFER_COMPLETE);
- cpu_irq_restore(flags);
- return;
- }
- }
-
-uhd_pipe_trans_complet_end:
- /* Call callback to signal end of transfer */
- _uhd_pipe_finish_job(p_callback_para->pipe_num, UHD_TRANS_NOERROR);
- return;
-}
-
-/**
- * \internal
- * \brief Aborts the on-going transfer on a pipe
- *
- * \param pipe Pipe number
- * \param status Reason of abort
- */
-static void _uhd_ep_abort_pipe(uint8_t pipe, uhd_trans_status_t status)
-{
- usb_host_pipe_freeze(&dev, pipe);
- _uhd_pipe_finish_job(pipe, status);
-}
-
-/**
- * \internal
- * \brief Call the callback linked to the end of pipe transfer
- *
- * \param pipe Pipe number
- * \param status Status of the transfer
- */
-static void _uhd_pipe_finish_job(uint8_t pipe, uhd_trans_status_t status)
-{
- uhd_pipe_job_t *ptr_job;
-
- struct usb_host_pipe_config cfg;
- usb_host_pipe_get_config(&dev, pipe, &cfg);
-
- /* Get job corresponding at endpoint */
- ptr_job = &uhd_pipe_job[pipe - 1];
- if (ptr_job->busy == false) {
- return; // No job running
- }
- /* In case of abort, free the internal buffer */
- if (ptr_job->buf_internal != NULL) {
- free(ptr_job->buf_internal);
- ptr_job->buf_internal = NULL;
- }
- ptr_job->busy = false;
- if (NULL == ptr_job->call_end) {
- return; // No callback linked to job
- }
- ptr_job->call_end(cfg.device_address,
- cfg.endpoint_address,
- status, ptr_job->nb_trans);
-}
-
-/**
- * \internal
- * \brief Manages pipe endpoint error callback
- *
- * \param module_inst Pointer to USB module instance
- * \param pointer Pointer to USB pipe transfer callback status parameters
- */
-static void _uhd_ep_error(struct usb_module *module_inst, void *pointer)
-{
- uhd_trans_status_t uhd_error;
- struct usb_pipe_callback_parameter *p_callback_para;
- p_callback_para = (struct usb_pipe_callback_parameter *)pointer;
-
- dbg_print("Tr Error %x\n", p_callback_para->pipe_num);
- /* Get and ack error */
- switch(p_callback_para->pipe_error_status) {
- case USB_STATUS_PIPE_DTGLER:
- uhd_error = UHD_TRANS_DT_MISMATCH;
- break;
- case USB_STATUS_PIPE_TOUTER:
- uhd_error = UHD_TRANS_NOTRESPONDING;
- break;
- case USB_STATUS_PIPE_CRC16ER:
- uhd_error = UHD_TRANS_CRC;
- break;
- case USB_STATUS_PIPE_DAPIDER:
- case USB_STATUS_PIPE_PIDER:
- uhd_error = UHD_TRANS_PIDFAILURE;
- break;
- default:
- uhd_error = UHD_TRANS_TIMEOUT;
- break;
- }
-
- _uhd_ep_abort_pipe(p_callback_para->pipe_num, uhd_error);
-}
-
-/**
- * \internal
- * \brief Manages pipe endpoint stall interrupt
- *
- * \param module_inst Pointer to USB module instance
- * \param pointer Pointer to USB pipe transfer callback status parameters
- */
-static void _uhd_ep_stall(struct usb_module *module_inst, void *pointer)
-{
- struct usb_pipe_callback_parameter *p_callback_para;
- p_callback_para = (struct usb_pipe_callback_parameter *)pointer;
-
- dbg_print("Tr Stall %x\n", p_callback_para->pipe_num);
- usb_host_pipe_clear_toggle(&dev, p_callback_para->pipe_num);
- _uhd_ep_abort_pipe(p_callback_para->pipe_num, UHD_TRANS_STALL);
-}
-
-bool uhd_ep0_alloc(usb_add_t add, uint8_t ep_size)
-{
- struct usb_host_pipe_config cfg;
-
- if (ep_size < 8) {
- return false;
- }
-
- usb_host_pipe_get_config_defaults(&cfg);
- cfg.device_address = add;
- cfg.size = ep_size;
- cfg.binterval = 0;
- usb_host_pipe_set_config(&dev,0,&cfg);
- usb_host_pipe_register_callback(&dev, 0,
- USB_HOST_PIPE_CALLBACK_TRANSFER_COMPLETE, _uhd_ep0_transfer_complete);
- usb_host_pipe_register_callback(&dev, 0,
- USB_HOST_PIPE_CALLBACK_ERROR, _uhd_ep0_error);
- usb_host_pipe_register_callback(&dev, 0,
- USB_HOST_PIPE_CALLBACK_SETUP, _uhd_ep0_setup);
- usb_host_pipe_register_callback(&dev, 0,
- USB_HOST_PIPE_CALLBACK_STALL, _uhd_ep0_stall);
- /* Always enable stall and error interrupts of control endpoint */
- usb_host_pipe_enable_callback(&dev,0,USB_HOST_PIPE_CALLBACK_TRANSFER_COMPLETE);
- usb_host_pipe_enable_callback(&dev,0,USB_HOST_PIPE_CALLBACK_ERROR);
- usb_host_pipe_enable_callback(&dev,0,USB_HOST_PIPE_CALLBACK_SETUP);
- usb_host_pipe_enable_callback(&dev,0,USB_HOST_PIPE_CALLBACK_STALL);
- return true;
-}
-
-bool uhd_ep_alloc(usb_add_t add, usb_ep_desc_t *ep_desc)
-{
- uint8_t pipe = 1;
- struct usb_host_pipe_config cfg;
- uint8_t ep_type;
- uint8_t ep_interval;
-
- for (pipe = 1; pipe < USB_PIPE_NUM; pipe++) {
- usb_host_pipe_get_config(&dev, pipe, &cfg);
- if (cfg.pipe_type != USB_HOST_PIPE_TYPE_DISABLE) {
- continue;
- }
- usb_host_pipe_get_config_defaults(&cfg);
- /* Enable pipe */
- ep_type = (ep_desc->bmAttributes & USB_EP_TYPE_MASK) + 1;
- if (ep_type == USB_HOST_PIPE_TYPE_BULK) {
- ep_interval = 0; // Ignore bInterval for bulk endpoint
- } else {
- ep_interval = ep_desc->bInterval;
- }
- cfg.device_address = add;
- cfg.endpoint_address = ep_desc->bEndpointAddress;
- cfg.pipe_type = (enum usb_host_pipe_type)ep_type;
- cfg.binterval = ep_interval;
- cfg.size = le16_to_cpu(ep_desc->wMaxPacketSize);
- usb_host_pipe_set_config(&dev,pipe,&cfg);
-
- usb_host_pipe_register_callback(&dev, pipe,
- USB_HOST_PIPE_CALLBACK_TRANSFER_COMPLETE, _uhd_pipe_trans_complete);
- usb_host_pipe_register_callback(&dev,pipe,
- USB_HOST_PIPE_CALLBACK_ERROR, _uhd_ep_error);
- usb_host_pipe_register_callback(&dev,pipe,
- USB_HOST_PIPE_CALLBACK_STALL, _uhd_ep_stall);
- /* Enable endpoint interrupts */
- usb_host_pipe_enable_callback(&dev,pipe,USB_HOST_PIPE_CALLBACK_TRANSFER_COMPLETE);
- usb_host_pipe_enable_callback(&dev,pipe,USB_HOST_PIPE_CALLBACK_ERROR);
- usb_host_pipe_enable_callback(&dev,pipe,USB_HOST_PIPE_CALLBACK_STALL);
- return true;
- }
- return false;
-}
-
-
-void uhd_ep_free(usb_add_t add, usb_ep_t endp)
-{
- uint8_t usb_pipe = 0;
- struct usb_host_pipe_config cfg;
-
- /* Search endpoint(s) in all pipes */
- for (usb_pipe = 0; usb_pipe < USB_PIPE_NUM; usb_pipe++) {
- usb_host_pipe_get_config(&dev, usb_pipe, &cfg);
-
- if (cfg.pipe_type == USB_HOST_PIPE_TYPE_DISABLE) {
- continue;
- }
-
- if (add != cfg.device_address) {
- continue;
- }
-
- if (endp != 0xFF) {
- /* Disable specific endpoint number */
- if (!((endp == 0) && (0 == cfg.endpoint_address))) {
- /* It is not the control endpoint */
- if (endp != cfg.endpoint_address) {
- continue; // Mismatch
- }
- }
- }
-
- if (usb_pipe == 0) {
- /* Disable and stop transfer on control endpoint */
- if (cfg.device_address == add) {
- usb_host_pipe_freeze(&dev, 0);
- if (uhd_ctrl_request_timeout ||
- (uhd_ctrl_request_first != NULL)) {
- _uhd_ctrl_request_end(UHD_TRANS_DISCONNECT);
- }
- continue;
- }
- }
-
- /* Endpoint interrupt, bulk or isochronous */
- /* Disable and stop transfer on this pipe */
- usb_host_pipe_freeze(&dev, usb_pipe);
- _uhd_pipe_finish_job(usb_pipe, UHD_TRANS_DISCONNECT);
- }
-}
-
-bool uhd_ep_run(
- usb_add_t add,
- usb_ep_t endp,
- bool b_shortpacket,
- uint8_t *buf,
- iram_size_t buf_size,
- uint16_t timeout,
- uhd_callback_trans_t callback)
-{
- irqflags_t flags;
- uhd_pipe_job_t *ptr_job;
- uint8_t pipe = 0;
-
- struct usb_pipe_callback_parameter callback_para;
-
- pipe = _uhd_get_pipe(add,endp);
- if (!pipe) {
- return false;
- }
- /* Get job about pipe */
- ptr_job = &uhd_pipe_job[pipe - 1];
- flags = cpu_irq_save();
- if (ptr_job->busy == true) {
- cpu_irq_restore(flags);
- return false; // Job already on going
- }
- ptr_job->busy = true;
-
- /* No job running. Let's setup a new one. */
- ptr_job->buf = buf;
- ptr_job->buf_size = buf_size;
- ptr_job->nb_trans = 0;
- ptr_job->timeout = timeout;
- ptr_job->b_shortpacket = b_shortpacket;
- ptr_job->call_end = callback;
- cpu_irq_restore(flags);
-
- /* Request first transfer */
- callback_para.pipe_num = pipe;
- callback_para.transfered_size = 0;
- callback_para.required_size = 0;
- _uhd_pipe_trans_complete(&dev, &callback_para);
- return true;
-}
-
-void uhd_ep_abort(usb_add_t add, usb_ep_t endp)
-{
- uint8_t usb_pipe = 0;
-
- usb_pipe = _uhd_get_pipe(add, endp);
- if (usb_pipe) {
- _uhd_ep_abort_pipe(usb_pipe, UHD_TRANS_ABORTED);
- }
-}
-
-/** @} */
diff --git a/atmel-samd/boards/arduino_zero/conf_access.h b/atmel-samd/boards/arduino_zero/conf_access.h
new file mode 100644
index 0000000000..8cf104e69c
--- /dev/null
+++ b/atmel-samd/boards/arduino_zero/conf_access.h
@@ -0,0 +1,115 @@
+/**
+ * \file
+ *
+ * \brief Memory access control configuration file.
+ *
+ * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * 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
+ * EXPRESSLY AND SPECIFICALLY 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.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Atmel Support
+ */
+
+#ifndef _CONF_ACCESS_H_
+#define _CONF_ACCESS_H_
+
+#include "compiler.h"
+#include "board.h"
+
+
+/*! \name Activation of Logical Unit Numbers
+ */
+//! @{
+#define LUN_0 ENABLE //!< On-Chip Virtual Memory.
+#define LUN_1 DISABLE //!< AT45DBX Data Flash.
+#define LUN_2 DISABLE //!< SD/MMC Card over SPI.
+#define LUN_3 DISABLE //!< SD/MMC Card over MCI Slot 0.
+#define LUN_4 DISABLE
+#define LUN_5 DISABLE
+#define LUN_6 DISABLE
+#define LUN_7 DISABLE
+#define LUN_USB DISABLE //!< Host Mass-Storage Memory.
+//! @}
+
+/*! \name LUN 0 Definitions
+ */
+//! @{
+#define LUN_0_INCLUDE "rom_fs.h"
+#define Lun_0_test_unit_ready rom_fs_test_unit_ready
+#define Lun_0_read_capacity rom_fs_read_capacity
+#define Lun_0_unload NULL /* Can not be unloaded */
+#define Lun_0_wr_protect rom_fs_wr_protect
+#define Lun_0_removal rom_fs_removal
+#define Lun_0_usb_read_10 rom_fs_usb_read_10
+#define Lun_0_usb_write_10 rom_fs_usb_write_10
+#define LUN_0_NAME "\"On-Chip ROM\""
+//! @}
+
+#define MEM_USB LUN_USB
+
+/*! \name Actions Associated with Memory Accesses
+ *
+ * Write here the action to associate with each memory access.
+ *
+ * \warning Be careful not to waste time in order not to disturb the functions.
+ */
+//! @{
+#define memory_start_read_action(nb_sectors)
+#define memory_stop_read_action()
+#define memory_start_write_action(nb_sectors)
+#define memory_stop_write_action()
+//! @}
+
+/*! \name Activation of Interface Features
+ */
+//! @{
+#define ACCESS_USB true //!< MEM <-> USB interface.
+#define ACCESS_MEM_TO_RAM false //!< MEM <-> RAM interface.
+#define ACCESS_STREAM false //!< Streaming MEM <-> MEM interface.
+#define ACCESS_STREAM_RECORD false //!< Streaming MEM <-> MEM interface in record mode.
+#define ACCESS_MEM_TO_MEM false //!< MEM <-> MEM interface.
+#define ACCESS_CODEC false //!< Codec interface.
+//! @}
+
+/*! \name Specific Options for Access Control
+ */
+//! @{
+#define GLOBAL_WR_PROTECT false //!< Management of a global write protection.
+//! @}
+
+
+#endif // _CONF_ACCESS_H_
diff --git a/atmel-samd/boards/arduino_zero/conf_usb.h b/atmel-samd/boards/arduino_zero/conf_usb.h
index 70035e64a1..d1ee1e8493 100644
--- a/atmel-samd/boards/arduino_zero/conf_usb.h
+++ b/atmel-samd/boards/arduino_zero/conf_usb.h
@@ -22,7 +22,24 @@
# define USB_DEVICE_PRODUCT_NAME "Arduino Zero"
#endif
// #define USB_DEVICE_SERIAL_NAME "12...EF"
+#define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number
+#define USB_DEVICE_GET_SERIAL_NAME_LENGTH 32
+extern char serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH];
+//! Control endpoint size
+#define USB_DEVICE_EP_CTRL_SIZE 64
+
+//! Two interfaces for this device (CDC COM + CDC DATA + MSC)
+#define USB_DEVICE_NB_INTERFACE 3
+
+// (3 | USB_EP_DIR_IN) // CDC Notify endpoint
+// (4 | USB_EP_DIR_IN) // CDC TX
+// (5 | USB_EP_DIR_OUT) // CDC RX
+// (1 | USB_EP_DIR_IN) // MSC IN
+// (2 | USB_EP_DIR_OUT) // MSC OUT
+#define USB_DEVICE_MAX_EP 5
+
+#define UDI_CDC_PORT_NB 1
#define UDI_CDC_ENABLE_EXT(port) mp_cdc_enable(port)
extern bool mp_cdc_enable(uint8_t port);
#define UDI_CDC_DISABLE_EXT(port) mp_cdc_disable(port)
@@ -40,5 +57,94 @@ void usb_rx_notify(void);
#define UDI_CDC_SET_DTR_EXT(port,set)
#define UDI_CDC_SET_RTS_EXT(port,set)
-#include "udi_cdc_conf.h" // At the end of conf_usb.h file
+/**
+ * USB CDC low level configuration
+ * In standalone these configurations are defined by the CDC module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+
+#define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint
+#define UDI_CDC_DATA_EP_IN_0 (4 | USB_EP_DIR_IN) // TX
+#define UDI_CDC_DATA_EP_OUT_0 (5 | USB_EP_DIR_OUT) // RX
+
+//! Interface numbers
+#define UDI_CDC_COMM_IFACE_NUMBER_0 0
+#define UDI_CDC_DATA_IFACE_NUMBER_0 1
+
+/**
+ * Configuration of MSC interface
+ * @{
+ */
+//! Vendor name and Product version of MSC interface
+#define UDI_MSC_GLOBAL_VENDOR_ID \
+ 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' '
+#define UDI_MSC_GLOBAL_PRODUCT_VERSION \
+ '1', '.', '0', '0'
+
+//! Interface callback definition
+#define UDI_MSC_ENABLE_EXT() mp_msc_enable()
+extern bool mp_msc_enable();
+#define UDI_MSC_DISABLE_EXT() mp_msc_disable()
+extern void mp_msc_disable();
+
+//! Enable id string of interface to add an extra USB string
+#define UDI_MSC_STRING_ID 5
+
+/**
+ * USB MSC low level configuration
+ * In standalone these configurations are defined by the MSC module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_MSC_EP_IN (1 | USB_EP_DIR_IN)
+#define UDI_MSC_EP_OUT (2 | USB_EP_DIR_OUT)
+
+//! Interface number
+#define UDI_MSC_IFACE_NUMBER 2
+
+/**
+ * Description of Composite Device
+ * @{
+ */
+//! USB Interfaces descriptor structure
+#define UDI_COMPOSITE_DESC_T \
+ usb_iad_desc_t udi_cdc_iad; \
+ udi_cdc_comm_desc_t udi_cdc_comm; \
+ udi_cdc_data_desc_t udi_cdc_data; \
+ udi_msc_desc_t udi_msc
+
+//! USB Interfaces descriptor value for Full Speed
+#define UDI_COMPOSITE_DESC_FS \
+ .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
+ .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
+ .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \
+ .udi_msc = UDI_MSC_DESC_FS
+
+//! USB Interfaces descriptor value for High Speed
+#define UDI_COMPOSITE_DESC_HS \
+ .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
+ .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
+ .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \
+ .udi_msc = UDI_MSC_DESC_HS
+
+//! USB Interface APIs
+#define UDI_COMPOSITE_API \
+ &udi_api_cdc_comm, \
+ &udi_api_cdc_data, \
+ &udi_api_msc
+//@}
+
+/**
+ * USB Device Driver Configuration
+ * @{
+ */
+//@}
+
+//! The includes of classes and other headers must be done at the end of this file to avoid compile error
+#include "udi_cdc.h"
+#include "udi_msc.h"
+
#endif
diff --git a/atmel-samd/boards/arduino_zero/mpconfigboard.mk b/atmel-samd/boards/arduino_zero/mpconfigboard.mk
index 0351539007..97e27229fa 100644
--- a/atmel-samd/boards/arduino_zero/mpconfigboard.mk
+++ b/atmel-samd/boards/arduino_zero/mpconfigboard.mk
@@ -1 +1,3 @@
LD_FILE = boards/samd21x18.ld
+USB_VID = 0x2341
+USB_PID = 0x024D
diff --git a/atmel-samd/boards/feather_m0_bluefruit_le/conf_access.h b/atmel-samd/boards/feather_m0_bluefruit_le/conf_access.h
new file mode 100644
index 0000000000..8cf104e69c
--- /dev/null
+++ b/atmel-samd/boards/feather_m0_bluefruit_le/conf_access.h
@@ -0,0 +1,115 @@
+/**
+ * \file
+ *
+ * \brief Memory access control configuration file.
+ *
+ * Copyright (c) 2014-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * 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
+ * EXPRESSLY AND SPECIFICALLY 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.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit Atmel Support
+ */
+
+#ifndef _CONF_ACCESS_H_
+#define _CONF_ACCESS_H_
+
+#include "compiler.h"
+#include "board.h"
+
+
+/*! \name Activation of Logical Unit Numbers
+ */
+//! @{
+#define LUN_0 ENABLE //!< On-Chip Virtual Memory.
+#define LUN_1 DISABLE //!< AT45DBX Data Flash.
+#define LUN_2 DISABLE //!< SD/MMC Card over SPI.
+#define LUN_3 DISABLE //!< SD/MMC Card over MCI Slot 0.
+#define LUN_4 DISABLE
+#define LUN_5 DISABLE
+#define LUN_6 DISABLE
+#define LUN_7 DISABLE
+#define LUN_USB DISABLE //!< Host Mass-Storage Memory.
+//! @}
+
+/*! \name LUN 0 Definitions
+ */
+//! @{
+#define LUN_0_INCLUDE "rom_fs.h"
+#define Lun_0_test_unit_ready rom_fs_test_unit_ready
+#define Lun_0_read_capacity rom_fs_read_capacity
+#define Lun_0_unload NULL /* Can not be unloaded */
+#define Lun_0_wr_protect rom_fs_wr_protect
+#define Lun_0_removal rom_fs_removal
+#define Lun_0_usb_read_10 rom_fs_usb_read_10
+#define Lun_0_usb_write_10 rom_fs_usb_write_10
+#define LUN_0_NAME "\"On-Chip ROM\""
+//! @}
+
+#define MEM_USB LUN_USB
+
+/*! \name Actions Associated with Memory Accesses
+ *
+ * Write here the action to associate with each memory access.
+ *
+ * \warning Be careful not to waste time in order not to disturb the functions.
+ */
+//! @{
+#define memory_start_read_action(nb_sectors)
+#define memory_stop_read_action()
+#define memory_start_write_action(nb_sectors)
+#define memory_stop_write_action()
+//! @}
+
+/*! \name Activation of Interface Features
+ */
+//! @{
+#define ACCESS_USB true //!< MEM <-> USB interface.
+#define ACCESS_MEM_TO_RAM false //!< MEM <-> RAM interface.
+#define ACCESS_STREAM false //!< Streaming MEM <-> MEM interface.
+#define ACCESS_STREAM_RECORD false //!< Streaming MEM <-> MEM interface in record mode.
+#define ACCESS_MEM_TO_MEM false //!< MEM <-> MEM interface.
+#define ACCESS_CODEC false //!< Codec interface.
+//! @}
+
+/*! \name Specific Options for Access Control
+ */
+//! @{
+#define GLOBAL_WR_PROTECT false //!< Management of a global write protection.
+//! @}
+
+
+#endif // _CONF_ACCESS_H_
diff --git a/atmel-samd/boards/feather_m0_bluefruit_le/conf_usb.h b/atmel-samd/boards/feather_m0_bluefruit_le/conf_usb.h
index 70035e64a1..05de167760 100644
--- a/atmel-samd/boards/feather_m0_bluefruit_le/conf_usb.h
+++ b/atmel-samd/boards/feather_m0_bluefruit_le/conf_usb.h
@@ -15,14 +15,31 @@
//! USB Device string definitions (Optional)
#ifndef USB_DEVICE_MANUFACTURE_NAME
-# define USB_DEVICE_MANUFACTURE_NAME "Arduino LLC"
+# define USB_DEVICE_MANUFACTURE_NAME "Adafruit"
#endif
#ifndef USB_DEVICE_PRODUCT_NAME
-# define USB_DEVICE_PRODUCT_NAME "Arduino Zero"
+# define USB_DEVICE_PRODUCT_NAME "Feather M0 Bluefruit LE"
#endif
-// #define USB_DEVICE_SERIAL_NAME "12...EF"
+#define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number
+#define USB_DEVICE_GET_SERIAL_NAME_LENGTH 32
+extern char serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH];
+
+//! Control endpoint size
+#define USB_DEVICE_EP_CTRL_SIZE 64
+
+//! Two interfaces for this device (CDC COM + CDC DATA + MSC)
+#define USB_DEVICE_NB_INTERFACE 3
+
+// (3 | USB_EP_DIR_IN) // CDC Notify endpoint
+// (4 | USB_EP_DIR_IN) // CDC TX
+// (5 | USB_EP_DIR_OUT) // CDC RX
+// (1 | USB_EP_DIR_IN) // MSC IN
+// (2 | USB_EP_DIR_OUT) // MSC OUT
+#define USB_DEVICE_MAX_EP 5
+
+#define UDI_CDC_PORT_NB 1
#define UDI_CDC_ENABLE_EXT(port) mp_cdc_enable(port)
extern bool mp_cdc_enable(uint8_t port);
#define UDI_CDC_DISABLE_EXT(port) mp_cdc_disable(port)
@@ -40,5 +57,94 @@ void usb_rx_notify(void);
#define UDI_CDC_SET_DTR_EXT(port,set)
#define UDI_CDC_SET_RTS_EXT(port,set)
-#include "udi_cdc_conf.h" // At the end of conf_usb.h file
+/**
+ * USB CDC low level configuration
+ * In standalone these configurations are defined by the CDC module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+
+#define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint
+#define UDI_CDC_DATA_EP_IN_0 (4 | USB_EP_DIR_IN) // TX
+#define UDI_CDC_DATA_EP_OUT_0 (5 | USB_EP_DIR_OUT) // RX
+
+//! Interface numbers
+#define UDI_CDC_COMM_IFACE_NUMBER_0 0
+#define UDI_CDC_DATA_IFACE_NUMBER_0 1
+
+/**
+ * Configuration of MSC interface
+ * @{
+ */
+//! Vendor name and Product version of MSC interface
+#define UDI_MSC_GLOBAL_VENDOR_ID \
+ 'A', 'T', 'M', 'E', 'L', ' ', ' ', ' '
+#define UDI_MSC_GLOBAL_PRODUCT_VERSION \
+ '1', '.', '0', '0'
+
+//! Interface callback definition
+#define UDI_MSC_ENABLE_EXT() mp_msc_enable()
+extern bool mp_msc_enable();
+#define UDI_MSC_DISABLE_EXT() mp_msc_disable()
+extern void mp_msc_disable();
+
+//! Enable id string of interface to add an extra USB string
+#define UDI_MSC_STRING_ID 5
+
+/**
+ * USB MSC low level configuration
+ * In standalone these configurations are defined by the MSC module.
+ * For composite device, these configuration must be defined here
+ * @{
+ */
+//! Endpoint numbers definition
+#define UDI_MSC_EP_IN (1 | USB_EP_DIR_IN)
+#define UDI_MSC_EP_OUT (2 | USB_EP_DIR_OUT)
+
+//! Interface number
+#define UDI_MSC_IFACE_NUMBER 2
+
+/**
+ * Description of Composite Device
+ * @{
+ */
+//! USB Interfaces descriptor structure
+#define UDI_COMPOSITE_DESC_T \
+ usb_iad_desc_t udi_cdc_iad; \
+ udi_cdc_comm_desc_t udi_cdc_comm; \
+ udi_cdc_data_desc_t udi_cdc_data; \
+ udi_msc_desc_t udi_msc
+
+//! USB Interfaces descriptor value for Full Speed
+#define UDI_COMPOSITE_DESC_FS \
+ .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
+ .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
+ .udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \
+ .udi_msc = UDI_MSC_DESC_FS
+
+//! USB Interfaces descriptor value for High Speed
+#define UDI_COMPOSITE_DESC_HS \
+ .udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
+ .udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
+ .udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \
+ .udi_msc = UDI_MSC_DESC_HS
+
+//! USB Interface APIs
+#define UDI_COMPOSITE_API \
+ &udi_api_cdc_comm, \
+ &udi_api_cdc_data, \
+ &udi_api_msc
+//@}
+
+/**
+ * USB Device Driver Configuration
+ * @{
+ */
+//@}
+
+//! The includes of classes and other headers must be done at the end of this file to avoid compile error
+#include "udi_cdc.h"
+#include "udi_msc.h"
+
#endif
diff --git a/atmel-samd/boards/feather_m0_bluefruit_le/mpconfigboard.mk b/atmel-samd/boards/feather_m0_bluefruit_le/mpconfigboard.mk
index 6948e10dfc..b98d45db8b 100644
--- a/atmel-samd/boards/feather_m0_bluefruit_le/mpconfigboard.mk
+++ b/atmel-samd/boards/feather_m0_bluefruit_le/mpconfigboard.mk
@@ -1 +1,3 @@
LD_FILE = boards/samd21x18-bootloader.ld
+USB_VID = 0x239A
+USB_PID = 0x000B
diff --git a/atmel-samd/main.c b/atmel-samd/main.c
index 42dddb8d3b..555a91e12c 100644
--- a/atmel-samd/main.c
+++ b/atmel-samd/main.c
@@ -275,6 +275,21 @@ struct usart_module usart_instance;
__attribute__((__aligned__(TRACE_BUFFER_SIZE * sizeof(uint32_t)))) uint32_t mtb[TRACE_BUFFER_SIZE];
#endif
+// Serial number as hex characters.
+char serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH];
+void load_serial_number(void) {
+ char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
+ 'B', 'C', 'D', 'E', 'F'};
+ uint32_t* addresses[4] = {(uint32_t *) 0x0080A00C, (uint32_t *) 0x0080A040,
+ (uint32_t *) 0x0080A044, (uint32_t *) 0x0080A048};
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 8; j++) {
+ uint8_t nibble = (*(addresses[i]) >> j * 4) & 0xf;
+ serial_number[i * 8 + j] = nibble_to_hex[nibble];
+ }
+ }
+}
+
void samd21_init(void) {
#ifdef ENABLE_MICRO_TRACE_BUFFER
memset(mtb, 0, sizeof(mtb));
@@ -283,6 +298,9 @@ void samd21_init(void) {
REG_MTB_FLOW = ((uint32_t) mtb + TRACE_BUFFER_SIZE * sizeof(uint32_t)) & 0xFFFFFFF8;
REG_MTB_MASTER = 0x80000000 + 6;
#endif
+
+ load_serial_number();
+
irq_initialize_vectors();
cpu_irq_enable();
diff --git a/atmel-samd/mphalport.c b/atmel-samd/mphalport.c
index 08a0abfb99..a46af47cd8 100644
--- a/atmel-samd/mphalport.c
+++ b/atmel-samd/mphalport.c
@@ -1,5 +1,7 @@
#include
+#include "compiler.h"
+#include "asf/common/services/sleepmgr/sleepmgr.h"
#include "asf/common/services/usb/class/cdc/device/udi_cdc.h"
#include "asf/common2/services/delay/delay.h"
#include "asf/sam0/drivers/port/port.h"
@@ -33,6 +35,19 @@ int interrupt_char;
extern struct usart_module usart_instance;
+
+static volatile bool mp_msc_enabled = false;
+bool mp_msc_enable()
+{
+ mp_msc_enabled = true;
+ return true;
+}
+
+void mp_msc_disable()
+{
+ mp_msc_enabled = false;
+}
+
bool mp_cdc_enable(uint8_t port)
{
mp_cdc_enabled = true;
@@ -125,6 +140,10 @@ int receive_usb() {
int mp_hal_stdin_rx_chr(void) {
for (;;) {
+ // Process any mass storage transfers.
+ if (mp_msc_enabled) {
+ udi_msc_process_trans();
+ }
#ifdef USB_REPL
if (mp_cdc_enabled && usb_rx_count > 0) {
#ifdef MICROPY_HW_LED_RX
@@ -142,9 +161,9 @@ int mp_hal_stdin_rx_chr(void) {
return temp;
}
#endif
- // TODO(tannewt): Figure out how we can sleep while waiting for input and
- // add it here. The current UART implementation doesn't cause a wake.
- //__WFI();
+ // TODO(tannewt): Switch to callback/interrupt based UART so it can work
+ // with the sleepmgr.
+ sleepmgr_enter_sleep();
}
}
@@ -173,9 +192,21 @@ void mp_hal_set_interrupt_char(int c) {
}
void mp_hal_delay_ms(mp_uint_t delay) {
- delay_ms(delay);
+ // Process any mass storage transfers.
+ // TODO(tannewt): Actually account for how long the processing takes and
+ // subtract it from the delay.
+ if (mp_msc_enabled) {
+ udi_msc_process_trans();
+ }
+ delay_ms(delay);
}
void mp_hal_delay_us(mp_uint_t delay) {
- delay_us(delay);
+ // Process any mass storage transfers.
+ // TODO(tannewt): Actually account for how long the processing takes and
+ // subtract it from the delay.
+ if (mp_msc_enabled) {
+ udi_msc_process_trans();
+ }
+ delay_us(delay);
}
diff --git a/atmel-samd/rom_fs.c b/atmel-samd/rom_fs.c
new file mode 100644
index 0000000000..f0b01fa6b7
--- /dev/null
+++ b/atmel-samd/rom_fs.c
@@ -0,0 +1,123 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * 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.
+ */
+
+#include "rom_fs.h"
+
+#include "asf/common/services/usb/class/msc/device/udi_msc.h"
+#include "storage.h"
+
+//! This function tests memory state, and starts memory initialization
+//! @return Ctrl_status
+//! It is ready -> CTRL_GOOD
+//! Memory unplug -> CTRL_NO_PRESENT
+//! Not initialized or changed -> CTRL_BUSY
+//! An error occurred -> CTRL_FAIL
+Ctrl_status rom_fs_test_unit_ready(void)
+{
+ return CTRL_GOOD;
+}
+
+//! This function returns the address of the last valid sector
+//! @param uint32_t_nb_sector Pointer to number of sectors (sector=512 bytes)
+//! @return Ctrl_status
+//! It is ready -> CTRL_GOOD
+//! Memory unplug -> CTRL_NO_PRESENT
+//! Not initialized or changed -> CTRL_BUSY
+//! An error occurred -> CTRL_FAIL
+Ctrl_status rom_fs_read_capacity(uint32_t *uint32_t_nb_sector)
+{
+ *uint32_t_nb_sector = storage_get_block_count();
+ return CTRL_GOOD;
+}
+
+//! This function returns the write-protected mode
+//!
+//! @return true if the memory is protected
+//!
+bool rom_fs_wr_protect(void)
+{
+ return false;
+}
+
+//! This function informs about the memory type
+//!
+//! @return true if the memory is removable
+//!
+bool rom_fs_removal(void)
+{
+ return true;
+}
+
+// TODO(tannewt): Transfer more than a single sector at a time if we need more
+// speed.
+//! This function transfers the memory data to the USB MSC interface
+//!
+//! @param addr Sector address to start read
+//! @param nb_sector Number of sectors to transfer (sector=512 bytes)
+//!
+//! @return Ctrl_status
+//! It is ready -> CTRL_GOOD
+//! Memory unplug -> CTRL_NO_PRESENT
+//! Not initialized or changed -> CTRL_BUSY
+//! An error occurred -> CTRL_FAIL
+//!
+Ctrl_status rom_fs_usb_read_10(uint32_t addr, volatile uint16_t nb_sector)
+{
+ uint8_t sector_buffer[FLASH_BLOCK_SIZE];
+ for (uint16_t sector = 0; sector < nb_sector; sector++) {
+ storage_read_block(sector_buffer, addr + sector);
+ if (!udi_msc_trans_block(true, sector_buffer, FLASH_BLOCK_SIZE, NULL)) {
+ return CTRL_FAIL; // transfer aborted
+ }
+ }
+ return CTRL_GOOD;
+}
+
+
+//! This function transfers the USB MSC data to the memory
+//!
+//! @param addr Sector address to start write
+//! @param nb_sector Number of sectors to transfer (sector=512 bytes)
+//!
+//! @return Ctrl_status
+//! It is ready -> CTRL_GOOD
+//! Memory unplug -> CTRL_NO_PRESENT
+//! Not initialized or changed -> CTRL_BUSY
+//! An error occurred -> CTRL_FAIL
+//!
+Ctrl_status rom_fs_usb_write_10(uint32_t addr, uint16_t nb_sector)
+{
+ uint8_t sector_buffer[FLASH_BLOCK_SIZE];
+ for (uint16_t sector = 0; sector < nb_sector; sector++) {
+ if (!udi_msc_trans_block(false, sector_buffer, FLASH_BLOCK_SIZE, NULL)) {
+ return CTRL_FAIL; // transfer aborted
+ }
+ if (!storage_write_block(sector_buffer, addr + sector)) {
+ return CTRL_FAIL;
+ }
+ }
+ return CTRL_GOOD;
+}
diff --git a/atmel-samd/rom_fs.h b/atmel-samd/rom_fs.h
new file mode 100644
index 0000000000..8b1fe2de9e
--- /dev/null
+++ b/atmel-samd/rom_fs.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * 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.
+ */
+
+#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_ROM_FS_H__
+#define __MICROPY_INCLUDED_ATMEL_SAMD_ROM_FS_H__
+
+#include "asf/common/services/storage/ctrl_access/ctrl_access.h"
+
+
+Ctrl_status rom_fs_test_unit_ready(void);
+Ctrl_status rom_fs_read_capacity(uint32_t *u32_nb_sector);
+bool rom_fs_wr_protect(void);
+bool rom_fs_removal(void);
+Ctrl_status rom_fs_usb_read_10(uint32_t addr, uint16_t nb_sector);
+Ctrl_status rom_fs_usb_write_10(uint32_t addr, uint16_t nb_sector);
+
+#endif // __MICROPY_INCLUDED_ATMEL_SAMD_ROM_FS_H__
diff --git a/atmel-samd/storage.h b/atmel-samd/storage.h
index 9c1105244d..8b814c34e1 100644
--- a/atmel-samd/storage.h
+++ b/atmel-samd/storage.h
@@ -23,6 +23,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_STORAGE_H__
+#define __MICROPY_INCLUDED_ATMEL_SAMD_STORAGE_H__
+
+#include "mpconfigport.h"
#define FLASH_BLOCK_SIZE (512)
@@ -45,3 +49,5 @@ extern const struct _mp_obj_type_t flash_type;
struct _fs_user_mount_t;
void flash_init_vfs(struct _fs_user_mount_t *vfs);
+
+#endif // __MICROPY_INCLUDED_ATMEL_SAMD_STORAGE_H__