\documentclass[aspectratio=169,obeyspaces,spaces,hyphens,dvipsnames]{beamer}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}% http://ctan.org/pkg/lm
\usepackage{minted}
\usepackage{hyperref}
\usepackage{xcolor}
\usepackage{pgfplots}
\usepackage{tikz}
\usepackage[normalem]{ulem}
\usepackage{tabularx}

\usepackage{array,multirow,makecell}
\setcellgapes{1pt}
\makegapedcells

\mode<presentation>
\usetheme{Bootlin}

\def\signed #1{{\leavevmode\unskip\nobreak\hfil\penalty50\hskip2em
  \hbox{}\nobreak\hfil(#1)
  \parfillskip=0pt \finalhyphendemerits=0 \endgraf}}

\newsavebox\mybox
\newenvironment{aquote}[1]
  {\savebox\mybox{#1}\begin{quotation}}
  {\signed{\usebox\mybox}\end{quotation}}

\title{A tour of USB Device Controller (UDC) in Linux}
\authors{Hervé Codina}
\email{herve.codina@bootlin.com}
\slidesurl{https://bootlin.com/pub/conferences/}
\institute{Bootlin}
\conference{Embedded Linux Conference Europe 2023}

\begin{document}

\addtocontents{toc}{\protect\setcounter{tocdepth}{-1}}
\section{A tour of USB Device Controller (UDC) in Linux}
\addtocontents{toc}{\protect\setcounter{tocdepth}{2}}

\begin{frame}{Hervé Codina}
  \begin{itemize}
  \item Embedded Linux engineer at Bootlin
    \begin{itemize}
    \item Embedded Linux {\bf expertise}
    \item {\bf Development}, consulting and training
    \item Contributor to the {\bf Renesas RZ/N1 USBF} UDC driver in Linux
    \item Strong open-source focus
    \end{itemize}
  \item Open-source contributor
  \item Living in {\bf Toulouse}, France
  \end{itemize}
\end{frame}

\subsection{USB2.0 standard}

\begin{frame}{USB2.0 standard}
  \begin{columns}
    \column{0.5\textwidth}
    \begin{itemize}
      \item \url{https://www.usb.org/document-library/usb-20-specification}
      \item Released on April 27, 2000
      \item Defines the mechanical part, the electrical and communication protocol
      \item Publicly available
      \item Supports
      \begin{itemize}
    	\item High-speed (480 Mb/s)
    	\item Full-speed (12 Mb/s)
    	\item Low-speed (1.5 Mb/s)
      \end{itemize}
    \end{itemize}
    \column{0.5\textwidth}
    \begin{center}
      \includegraphics[width=1.0\textwidth]{graphics/usb20-logo.png}
                      {\tiny\break Extracted from the USB2.0 standard}
    \end{center}
  \end{columns}
\end{frame}

\begin{frame}{USB Bus}
  \begin{columns}
    \column{0.5\textwidth}
    \begin{center}
      \includegraphics[width=1.0\textwidth]{graphics/bus-topology.pdf}
    \end{center}
    \column{0.5\textwidth}
    \begin{itemize}
      \item Multiple devices using hubs
      \item Hot-plug devices
      \item Discoverable devices
      \item Each device has a unique address assigned by the host
    \end{itemize}
  \end{columns}
\end{frame}


\begin{frame}{Communication flow}
  \begin{itemize}
    \item USB transfers are initiated by the Host.
    \item A USB transfer is made of bus transactions
    \item Most bus transactions involve the transmission of up to three packets
    \begin{itemize}
      \item Token (IN, OUT, SETUP, ...)
      \begin{itemize}
        \item First packet in a transaction
        \item Identify transaction type and direction.
        \item Identify transaction recipient (USB device address, Endpoint number)
      \end{itemize}
      \item Data (DATA0, DATA1, ...)
      \begin{itemize}
        \item Contains the data related to the transaction
        \item Can be an empty data packet (zero-length packet)
        \item \code{wMaxPacketSize} size limit on each Endpoint (max 1024 bytes)
      \end{itemize}
      \item Handshake (ACK, NAK, STALL, ...)
      \begin{itemize}
        \item Indicates whether the transfer was successful.
      \end{itemize}
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Bulk transfers}
  \begin{itemize}
    \item Guaranteed delivery
    \item No guarantee of bandwidth or latency\newline
  \end{itemize}
  \begin{center}
    \includegraphics[width=0.5\textwidth]{graphics/xfer-bulk.pdf}
  \end{center}
\end{frame}

\begin{frame}{Interrupt transfers}
  \begin{itemize}
    \item Guaranteed maximum service period
    \item Retry on next period in case of delivery failure
    \item Interrupt: periodic polling from the host\newline
  \end{itemize}
  \begin{center}
    \includegraphics[width=0.5\textwidth]{graphics/xfer-bulk.pdf}
  \end{center}
\end{frame}

\begin{frame}{Isochronous transfers}
  \begin{itemize}
    \item Guaranteed bandwidth and data rate
    \item No retry in case of delivery failure\newline
  \end{itemize}
  \begin{center}
    \includegraphics[width=0.5\textwidth]{graphics/xfer-iso.pdf}
  \end{center}
\end{frame}

\begin{frame}{Control transfers}
  \begin{itemize}
    \item Intended to support configuration/command/status communication flow
  \end{itemize}
  \begin{center}
    \includegraphics[width=1.0\textwidth]{graphics/xfer-control.pdf}
  \end{center}
\end{frame}

\begin{frame}{Endpoints, Interfaces, Configuration}
  \begin{columns}
    \column{0.7\textwidth}
    \begin{itemize}
      \item {\bf Endpoint}: Terminus of a communication flow between the host and the
            device.
      \begin{itemize}
        \item Uniquely referenced (device address, endpoint number, direction)
        \item EP0 (IN/OUT): Used to configure and control the device (mandatory).
        \item Endpoints other than EP0 are function specific.
      \end{itemize}
      \item {\bf Interface}: Group of endpoints to provide a function.
      \begin{itemize}
        \item Several interfaces can be available at the same time (multi-function
            printer/scanner)
      \end{itemize}
      \item {\bf Configuration}: Device capabilities.
      \begin{itemize}
        \item Power budget, remote wake-up support, number of interfaces.
        \item One or more interfaces are present in each configuration.
        \item Only one configuration can be activated.
      \end{itemize}
    \end{itemize}
    \column{0.3\textwidth}
    \begin{center}
      \includegraphics[width=1.0\textwidth]{graphics/dev-communication.pdf}
    \end{center}
  \end{columns}
\end{frame}

\begin{frame}{Standard requests}
  \begin{itemize}
    \item Use control transfers through EP0.
  \end{itemize}
  \begin{columns}
    \column{0.5\textwidth}
    \begin{center}
      \includegraphics[width=0.8\textwidth]{graphics/stdreq-setup.png}
    \end{center}
    \column{0.5\textwidth}
    \begin{center}
      \includegraphics[width=0.8\textwidth]{graphics/stdreq-list.png}
    \end{center}
  \end{columns}
  \begin{center}
    {\tiny\break Extracted from the USB2.0 standard}
  \end{center}
\end{frame}

\begin{frame}{Device states}
  \begin{columns}
    \column{0.5\textwidth}
    \begin{center}
      \includegraphics[width=0.7\textwidth]{graphics/dev-state.png}
      {\tiny\break Extracted from the USB2.0 standard}
    \end{center}
    \column{0.5\textwidth}
    \begin{center}
      \tiny
%      %\includegraphics[width=0.7\textwidth]{graphics/dev-state-table.png}
      \begin{tabularx}{7cm}{|>{\hsize=0.4\hsize\linewidth=\hsize}X
                            |>{\hsize=1.6\hsize\linewidth=\hsize}X|}
      \hline
      \multicolumn{1}{|c|}{\it State} & \multicolumn{1}{c|}{\it Description} \\
      %{\it State} & {\it Description} \\
      \hline
      {\bf Attached} & Device is attached to the USB but is not powered. \\
      \hline
      {\bf Powered} & The host set VBUS. Device is powered but has not received
                      the USB reset.

                      It must not answer to any transaction. \\
      \hline
      {\bf Default} & Device received the USB reset.

                      It is addressable at the default USB address (address 0)
                      and answers to transaction on EP0 using this USB address. \\
      \hline
      {\bf Address} & The host assigned a unique device USB address using a
                      SET\_ADDRESS request.

                      Device is addressable at the address assigned and answers
                      to transactions on EP0 using this unique USB address. \\
      \hline
      {\bf Configured} & Device received a SET\_CONFIGURATION request.

                         Device is ready to use, its functions are available and
                         it answers to the transactions on all EPs. \\
      \hline
      {\bf Suspended} & Device enter the suspend state when it has observed no
                        bus activities for a specified period.

                        In suspended state, it maintains its internal status
                        including its address and configuration.

                        Suspended state is exited when there is bus activity. \\
      \hline
      \end{tabularx}
    \end{center}
  \end{columns}
\end{frame}

\begin{frame}{Bus enumeration}
  \begin{itemize}
    \item Detect devices, assign addresses, configure.
    \item Communication through standard requests.
    \item Enumeration sequence (somewhat simplified)
    \begin{enumerate}
      \item Device plugged to a powered port (the port is disabled).
      \begin{itemize}
        \item VBUS is available at the device side.
      \end{itemize}
      \item The device connects the pull-up data line resistor.
      \begin{itemize}
      \item The Hub detects the attachment and informs the host (status change).
      \end{itemize}
      \item The host asks the Hub for a port enable and a reset on that port.
      \begin{itemize}
        \item Following the reset, the device is in the Default state.
        \item It answers to the default address and EP0 is accessible.
      \end{itemize}
      \item The host assigns a unique address (SET\_ADDRESS request).
      \begin{itemize}
        \item The device is in the Address state.
        \item It answers to the assigned address and EP0 is accessible.
      \end{itemize}
      \item The host read the descriptors (GET\_DESCRIPTOR requests)
      \item The host configure the device (SET\_CONFIGURATION request).
      \begin{itemize}
        \item The device is in the Configured state.
        \item The interfaces available in the selected configuration and their
              endpoints are accessible.
      \end{itemize}
    \end{enumerate}
  \end{itemize}
\end{frame}

\subsection{Linux USB Device Controller (UDC)}

\begin{frame}{USB gadget (Linux as an USB device)}
  \begin{center}
    \includegraphics[width=0.8\textwidth]{graphics/usb-gadget.pdf}
  \end{center}
\end{frame}

\begin{frame}{UDC driver structure}
  \begin{itemize}
    \item Includes \kfileinclude{linux/usb/gadget.h}
    \begin{itemize}
      \item The Chapter 9 USB2.0 standard references (\kfileinclude{uapi/linux/usb/ch9.h}) included.
    \end{itemize}
    \item Provides hooks for device management (\kstruct{usb_gadget_ops})
    \item Provides hooks for endpoints management (\kstruct{usb_ep_ops})
    \item Uses functions from the Gadget Core API for
    \begin{itemize}
      \item Registering the UDC,
      \item Signaling USB events,
      \item Forwarding EP0 requests to the Gadget core,
      \item Signaling Endpoints end of transfers.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Gadget ops}
  \begin{block}{\code{linux/usb/gadget.h} (simplified, only basic hooks extracted)}
    \fontsize{8}{8}\selectfont
    \begin{minted}{c}
struct usb_gadget_ops {
	// ...
	int (*pullup) (struct usb_gadget *, int is_on);
	// ...
	int (*udc_start)(struct usb_gadget *,
			 struct usb_gadget_driver *);
	int (*udc_stop)(struct usb_gadget *);
	// ...
};
    \end{minted}
  \end{block}
\end{frame}

\begin{frame}{Gadget ops - udc\_start() / udc\_stop()}
  \begin{itemize}
    \item \code{udc_start()}: Start the UDC
    \begin{itemize}
      \item The UDC driver is going to be used and needs to start.
      \item Start VBUS monitoring (if possible)
      \item No USB transfer should be enabled at this time
    \end{itemize}
    \item \code{udc_stop()}: Stop the UDC
    \begin{itemize}
      \item The UDC driver is not used anymore.
      \item No more events can be signaled by the UDC.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Gadget ops - pullup()}
  \begin{itemize}
    \item \code{pullup()}: Activate or deactivate the data line pull-up
    \begin{itemize}
      \item The \code{pullup()} is called by the Gadget core after the VBUS
            detection is signaled.
      \item Activate (is\_on != 0)
      \begin{itemize}
            \item Connect the pull-up.
            \item USB connect detected by the host $\rightarrow$ Beginning of
                  USB activities (Bus enumeration).
      \end{itemize}
      \item Deactivate (is\_on == 0)
      \begin{itemize}
            \item Disconnect the pull-up
            \item USB disconnect detected by the host $\rightarrow$ End of
                  USB activities.
            \item No transfer anymore.
      \end{itemize}
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Endpoint ops}
  \begin{block}{\code{linux/usb/gadget.h} (simplified, only basic hooks extracted)}
    \fontsize{8}{8}\selectfont
    \begin{minted}{c}
struct usb_ep_ops {
	int (*enable) (struct usb_ep *ep,
		       const struct usb_endpoint_descriptor *desc);
	int (*disable) (struct usb_ep *ep);
	// ...
	struct usb_request *(*alloc_request) (struct usb_ep *ep,
					      gfp_t gfp_flags);
	void (*free_request) (struct usb_ep *ep, struct usb_request *req);

	int (*queue) (struct usb_ep *ep, struct usb_request *req,
		      gfp_t gfp_flags);
	int (*dequeue) (struct usb_ep *ep, struct usb_request *req);

	int (*set_halt) (struct usb_ep *ep, int value);
	int (*set_wedge) (struct usb_ep *ep);
	// ...
};
    \end{minted}
  \end{block}
\end{frame}
          
\begin{frame}{Endpoint ops - enable() / disable()}
  Endpoint chosen by the core among the available Endpoint list.
  \begin{itemize}
    \item \code{enable()}: Enable the endpoint
    \begin{itemize}
      \item Setup the endpoint based on \kstruct{usb_endpoint_descriptor}
      \item Configure the hardware to handle the endpoint.
    \end{itemize}
    \item \code{disable()}: Disable the endpoint
    \begin{itemize}
      \item Disable the endpoint at the hardware level.
      \item Complete all pending requests (\kfunc{usb_gadget_giveback_request} with \code{req.status = -ESHUTDOWN})
      \item The endpoint will not be used anymore.
    \end{itemize}
  \end{itemize}
  EP0 is always enabled, never disabled.
\end{frame}

\begin{frame}{Endpoint ops - set\_halt() / set\_wedge()}
  \begin{itemize}
    \item \code{set_halt()}: Set or clear the endpoint halt feature.
    \begin{itemize}
      \item Halted endpoint will return a STALL
      \item The Host \code{GET_STATUS(endpoint)} request returns the halt status.
      \item The Host \code{CLEAR_FEATURE(HALT_ENDPOINT)} request clears
            the halt state.
    \end{itemize}
    \item \code{set_wedge()}: Set the endpoint halt feature.
    \begin{itemize}
      \item Same as \code{set_halt(ep, 1)} except:
      \item The Host \code{CLEAR_FEATURE(HALT_ENDPOINT)} request {\bf does not}
            switch the endpoint to its normal state.
      \item Only a \code{set_halt(ep, 0)} can clear the halt state.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Request}
  \begin{itemize}
    \item Data exchanged using an endpoint (\kstruct{usb_request})
    \item Chained using a queue per endpoint
    \item IN endpoint (from device to host): Data to send.
    \begin{itemize}
      \item One request $\rightarrow$ One or more data packet (max packet size).
      \item Zero length packet can be added if needed.
    \end{itemize}
    \item OUT endpoint (from host to device): Data received.
    \begin{itemize}
      \item Merge received data packets up to the request size
      \item Zero length packet or short packet terminates the request
      \item Data Packet received cannot be split over several requests.
    \end{itemize}
    \item Give back to the Core using \kfunc{usb_gadget_giveback_request}.
  \end{itemize}
\end{frame}

\begin{frame}{Endpoint ops - alloc\_request() / free\_request()}
  \begin{itemize}
    \item \code{alloc_request()}: Allocate a request
    \begin{itemize}
      \item One or more requests can be allocated per endpoint.
      \item Can setup extra resources (DMA buffer)
      \item An allocated request can be used several times (i.e. queued and completed several times)
    \end{itemize}
    \item \code{free_request()}: Free a request
    \begin{itemize}
      \item The request is no longer used
      \item Release specific hardware request resources.
      \item Free the request
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Endpoint ops - queue() / dequeue()}
  \begin{itemize}
    \item \code{queue()}: Queue a request
    \begin{itemize}
      \item The request is queued to be processed.
      \item Automatically removed from queue at the end of processing.
      \item \kfunc{usb_gadget_giveback_request} called at the end of processing.
      \item Start the queue processing if not already done.
    \end{itemize}
    \item \code{dequeue()}: Dequeue a request
    \begin{itemize}
      \item Dequeue an queued request.
      \item Complete the request (\kfunc{usb_gadget_giveback_request} with \code{req.status = -ECONNRESET}).
      \item Was the first in queue? $\rightarrow$ Start processing the next request.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Core API}
  \begin{block}{\code{linux/usb/gadget.h} (simplified and commented, only basic functions extracted)}
    \fontsize{7}{7}\selectfont
    \begin{minted}{c}
/* Register the UDC */
extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);

/* Unregister the UDC */
extern void usb_del_gadget_udc(struct usb_gadget *gadget);

/* Notify the VBUS status, and try to connect or disconnect gadget */
extern void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status);

/* Notify the Core that a bus reset occurs */
extern void usb_gadget_udc_reset(struct usb_gadget *gadget,
				 struct usb_gadget_driver *driver);

/* Set gadget state */
extern void usb_gadget_set_state(struct usb_gadget *gadget, enum usb_device_state state);

/* Give a request back to the Core layer */
extern void usb_gadget_giveback_request(struct usb_ep *ep, struct usb_request *req);

struct usb_gadget_driver {
	//...
	/* Handle EP0 control requests */
	int	(*setup)(struct usb_gadget *, const struct usb_ctrlrequest *);
	//...
};
    \end{minted}
  \end{block}
\end{frame}

\begin{frame}[fragile]{myudc driver data - data \& ops}
  \begin{columns}
    \column{0.5\textwidth}
    \begin{block}{}
      \fontsize{6}{6}\selectfont
      \begin{minted}{c}
struct myudc_ep {
	struct usb_ep ep;
	struct list_head queue;
	struct myudc *myudc;
	u8 id;
	bool disabled;
	//...
};

struct myudc {
	struct usb_gadget gadget;
	struct usb_gadget_driver *driver;
	/* My udc hardware supports 8 Endpoints */
	struct myudc_ep ep[8];
	//...
};

//...
      \end{minted}
    \end{block}
    \column{0.5\textwidth}
    \begin{block}{}
      \fontsize{6}{6}\selectfont
      \begin{minted}{c}
static static struct usb_ep_ops myudc_ep_ops = {
	.enable = myudc_ep_enable,
	.disable = myudc_ep_disable,
	.queue = myudc_ep_queue,
	.dequeue = myudc_ep_dequeue,
	.set_halt = myudc_ep_set_halt,
	.set_wedge = myudc_ep_set_wedge,
	.alloc_request = myudc_ep_alloc_request,
	.free_request = myudc_ep_free_request,
}

...

static struct usb_gadget_ops myudc_gadget_ops = {
	.udc_start = myudc_udc_start,
	.udc_stop = myudc_udc_stop,
	.pullup = myudc_pullup,
};
      \end{minted}
    \end{block}
  \end{columns}
\end{frame}

\begin{frame}[fragile]{myudc driver data - endpoints information}
  \begin{columns}
    \column{0.5\textwidth}
    \begin{block}{}
      \fontsize{5}{5}\selectfont
      \begin{minted}{c}
struct myudc_ep_info {
	const char *name;
	struct usb_ep_caps caps;
	u16 maxpacket_limit;
};

#define EP_INFO(_name, _caps, _maxpacket_limit)      \
	{                                            \
		.name = _name,                       \
		.caps = _caps,                       \
		.maxpacket_limit = _maxpacket_limit, \
	}

/* Available endpoints (from hardware datasheet) */
static const struct myudc_ep_info myudc_ep_info[8] = {
	[0] = EP_INFO("ep0-ctrl",
		      USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL),
		      64),
	[1] = EP_INFO("ep1-bulk",
		      USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL),
		      512),
	// ...
	[4] = EP_INFO("ep5-int",
		      USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_ALL),
		      1024),
	// ...
	[7] = EP_INFO("ep7-iso",
		      USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL),
		      1024),
};
      \end{minted}
    \end{block}
    \column{0.5\textwidth}
    \begin{itemize}
    \item Used during \code{probe()} call to initialize endpoints.
    \item Endpoint name
    \begin{itemize}
      \item Format \code{"epN*"} with \code{N} the endpoint number
    \end{itemize}
    \item Endpoint capabilities \kfunc{USB_EP_CAPS}
    \item Endpoint max packet size limit
    \end{itemize}
  \end{columns}
\end{frame}


\begin{frame}[fragile]{UDC driver probe()}
  \begin{columns}
    \column{0.5\textwidth}
    \begin{itemize}
      \item Initialize gadget fields (\code{name}, \code{max_speed}, \code{ops})
      \item Initialize available endpoints
      \begin{itemize}
        \item Disabled (will be enabled later)
        \item Initialize the request queue
        \item Initialize endpoint fields (\code{name}, \code{ops})
        \item Set the endpoint capabilities (\code{caps})
        \item Set the maximum packet size limit (\kfunc{usb_ep_set_maxpacket_limit})
      \end{itemize}
      \item Set the specific EP0
      \item Set the available endpoint list (endpoints other than EP0)
      \item Register the UDC driver
    \end{itemize}
    \column{0.5\textwidth}
    \begin{block}{}
        \fontsize{5}{5}\selectfont
        \begin{minted}{c}
static int myudc_probe(struct platform_device *pdev)
{
	struct myudc_ep *myudc_ep;
	struct myudc *myudc;

	// 1. Allocate myudc
	myudc = devm_kzalloc(dev, sizeof(*myudc), GFP_KERNEL);
	// ...
	// 2. Initialize gadget fields
	myudc->gadget.name = "myudc";
	myudc->gadget.max_speed = USB_SPEED_HIGH;
	myudc->gadget.ops = &myudc_gadget_ops;
	// 3. Initialize endpoints
	INIT_LIST_HEAD(&myudc->gadget.ep_list);
	for (i = 0; i < ARRAY_SIZE(myudc->ep); i++) {
		myudc_ep = &myudc->myudc_ep[i];
		INIT_LIST_HEAD(&myudc_ep->queue);
		myudc_ep->id = i;
		myudc_ep->disabled = 1;
		myudc_ep->myudc = myudc;
		myudc_ep->ep.ops = &myudc_ep_ops;
		myudc_ep->ep.name = myudc_ep_info[i].name;
		myudc_ep->ep.caps = myudc_ep_info[i].caps;
		usb_ep_set_maxpacket_limit(&myudc_ep->ep,
					   myudc_ep_info[i].maxpacket_limit);
		// ...
		if (myudc_ep->id == 0) {
			//4.a Set the specific EP0
			myudc->gadget.ep0 = &myudc_ep->ep;
		} else {
			//4.b Add the endpoint to the available endpoint list
			INIT_LIST_HEAD(&myudc_ep->ep.ep_list);
			list_add_tail(&myudc_ep->ep.ep_list,
				      &myudc->gadget.ep_list);
		}
	}
	// ...
	// 5. Register the UDC driver
	return usb_add_gadget_udc(dev, &myudc->gadget);
}
      \end{minted}
    \end{block}
  \end{columns}
\end{frame}

\begin{frame}[fragile]{Startup \& Reset - VBUS en USB reset events}
  \begin{columns}
    \column{0.5\textwidth}
    \begin{itemize}
      \item VBUS change events
      \begin{itemize}
        \item Signal event to the core.
        \begin{itemize}
          \item it will call pullup (on/off).
        \end{itemize}
      \end{itemize}
    \end{itemize}
    \column{0.5\textwidth}
    \begin{block}{}
        \fontsize{5}{5}\selectfont
        \begin{minted}{c}
static void myudc_handler_vbus(struct myudc *myudc)
{
	bool is_vbus;
	// ...
	is_vbus = my_udc_get_vbus(myudc);
	if (is_vbus) {
		usb_udc_vbus_handler(&myudc->gadget, true);
		usb_gadget_set_state(&myudc->gadget, USB_STATE_POWERED);
	} else {
		usb_udc_vbus_handler(&myudc->gadget, false);
		usb_gadget_set_state(&myudc->gadget, USB_STATE_NOTATTACHED);
	}
	//...
}
      \end{minted}
    \end{block}
  \end{columns}
  \begin{columns}
    \column{0.5\textwidth}
    \begin{itemize}
      \item USB reset events
      \begin{itemize}
        \item Complete all pending requests
        \item Speed negotiated during USB reset
        \item Reset the address to the USB default address.
        \item Signal the reset to the core
        \item Only EP0 is available after a reset
      \end{itemize}
    \end{itemize}
    \column{0.5\textwidth}
    \begin{block}{}
        \fontsize{5}{5}\selectfont
        \begin{minted}{c}
static void myudc_handler_usb_reset(struct myudc *myudc)
{
	// ...

	for (i = 0; i < ARRAY_SIZE(myudc->ep); i++)
		myudc_ep_nuke(&myudc->ep[i], -ESHUTDOWN);

	myudc_disable_all_endpoints(myudc);

	/* Set speed */
	udc->gadget.speed = myudc_is_high_speed(myudc) ?
		USB_SPEED_HIGH : USB_SPEED_FULL;

	/* Use USB default address */
	myudc_set_usb_address(myudc, 0x00);

	/* Setup endpoint zero */
	myudc_ep0_setup(myudc);

	/* Signal the reset to the core */
	if (myudc->driver)
		usb_gadget_udc_reset(&myudc->gadget, myudc->driver);
}
      \end{minted}
    \end{block}
  \end{columns}
\end{frame}

\begin{frame}{Startup \& Reset - Putting all together}
  \begin{center}
    \includegraphics[width=0.7\textwidth]{graphics/startup-reset.pdf}
  \end{center}
\end{frame}

\begin{frame}{EP0 Control requests handling}
  \begin{itemize}
    \item Fully handled at UDC Level for some control requests
    \begin{itemize}
      \item \code{SET_ADDRESS}: Set the unique USB address
      \item \code{GET_STATUS(Device)}: Remote WakeUp, Self powered
      \item \code{GET_STATUS(Endpoint)}: Endpoint Halt state
      \item \code{{SET,CLEAR}_FEATURE(Device)}: Remote WakeUp
      \item \code{{SET,CLEAR}_FEATURE(Endpoint)}: Endpoint Halt state
    \end{itemize}
    \item Delegate to the Core for others \\
          \code{ret = myudc->driver->setup(&myudc->gadget, ctrlrequest)}
    \begin{itemize}
      \item The Core performs the related operations
      \item Queue a request in the EP0 queue for the data or status stage
      \begin{itemize}
        \item data stage if data (IN or OUT) are needed (control read/write)
        \item status stage if no data are needed (control without data)
      \end{itemize}
      \item Returns \ksym{USB_GADGET_DELAYED_STATUS} if status stage request will be
            queued later.
    \end{itemize}
    \item Process queue (IN or OUT) if needed.
    \item Don't forget the status stage (send/receive Zero length packet)
  \end{itemize}
\end{frame}

\begin{frame}{Other EP handling}
  \begin{itemize}
    \item Data processing done at the Core/Function level
    \item The UDC performs the data transfers
    \begin{itemize}
      \item Just process the EP queue according to the EP direction.
    \end{itemize}
  \end{itemize}
\end{frame}


\subsection{How to test?}

\begin{frame}{testusb}
  \begin{itemize}
    \item \url{http://www.linux-usb.org/usbtest/}
    \item A Bootlin blog post related to testusb
          (\url{https://bootlin.com/blog/test-a-linux-kernel-usb-device-controller-driver-with-testusb/})
    \item Quite old tool
    \item Host part (test tooling)
    \begin{itemize}
      \item Dedicated kernel driver: \code{usbtest.ko} (\kconfigval{CONFIG_USB_TEST}{m}).
      \item A user-space program that asks for test: \code{testusb} (kernel
        sources \kdir{tools/usb})
      \item \code{usbtest.ko} can hang on some failures (reboot needed).\\
            Use it on a dedicated tool board, not your workstation.
    \end{itemize}
    \item Target part (system under test)
    \begin{itemize}
      \item Precomposed \code{g_zero} gadget is sufficient (\kconfigval{CONFIG_USB_ZERO}{m})
      \item The UDC to be tested
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{testusb}
  \begin{itemize}
    \item On the target
    \begin{block}{}
      \fontsize{8}{8}\selectfont
      \begin{minted}{text}
# modprobe g_zero
      \end{minted}
    \end{block}
    \item On the host
    \begin{itemize}
      \item Transfers other than isochronous
      \begin{block}{}
        \fontsize{8}{8}\selectfont
        \begin{minted}{text}
# modprobe usbtest
# testusb -a -v512
[ 220.276460] usbtest 2-1:3.0: TEST 0: NOP
[ 220.292316] usbtest 2-1:3.0: TEST 1: write 1024 bytes 8 times
[ 220.324711] usbtest 2-1:3.0: TEST 2: read 1024 bytes 8 times
...
[ 223.250355] usbtest 2-1:3.0: TEST 29: Clear toggle between bulk writes 8 times
#
        \end{minted}
      \end{block}
      \item Isochronous transfers (supported by g\_zero running on the target)
      \begin{block}{}
        \fontsize{8}{8}\selectfont
        \begin{minted}{text}
# modprobe usbtest alt=1
# testusb -a -v512
...
#
        \end{minted}
      \end{block}
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{Interesting precomposed gadget}
  \begin{itemize}
    \item \code{g_mass_storage} (\kconfig{CONFIG_USB_MASS_STORAGE})
    \begin{itemize}
      \item Halts some endpoints.
      \item Useful to test the halt feature.
    \end{itemize}
    \item  \code{g_ether} (\kconfig{CONFIG_USB_ETH})
    \begin{itemize}
      \item Uses transfer sizes that are not a multiple of MaxPacketSize.
      \item Useful to test transfers spanned on multiple packets.
      \item The last packet can be less than MaxPacketSize.
    \end{itemize}
    \item  \code{g_serial} (\kconfig{CONFIG_USB_G_SERIAL})
    \begin{itemize}
      \item In a basic configuration, each byte sent is echoed.
      \item Test very short packets
      \item Easy to isolate transfers
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{g\_mass\_storage}
  Errors appear if the endpoint halt feature is not well implemented.\newline
  \begin{itemize}
    \item On the target
    \begin{itemize}
      \item Create a file for the mass storage
      \item Load the gadget
    \end{itemize}
    \begin{block}{}
      \fontsize{8}{8}\selectfont
      \begin{minted}{text}
# dd if=/dev/zero of=/tmp/storage.part bs=1M count=8
# modprobe g_mass_storage file=/tmp/storage.part
      \end{minted}
    \end{block}
    \item On the host
    \begin{itemize}
      \item New USB removable disk detected.
      \item Format the disk.
      \item Transfer files.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{g\_ether}
  One UDC USB request $\leftrightarrow$ one Ethernet packet.\\
  The completed UDC USB request size = The Ethernet packet size.\newline
  \begin{itemize}
    \item On the target
    \begin{itemize}
      \item Load the gadget
      \item Retrieve files from host
    \end{itemize}
    \begin{block}{}
      \fontsize{8}{8}\selectfont
      \begin{minted}{text}
# modprobe g_ether
# wget http://192.168.0.106:8080/test_file.bin
      \end{minted}
    \end{block}
    \item On the host
    \begin{itemize}
      \item Run a web server to serve various file sizes.
      \item Trace the Ethernet transfers (Wireshark).
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{g\_serial}
  Each character typed on the host is echoed. \\
  When your hit 'enter', the whole buffer is echoed.\newline
  \begin{itemize}
    \item On the target
    \begin{itemize}
      \item Load the gadget
      \item Do a loopback
    \end{itemize}
    \begin{block}{}
      \fontsize{8}{8}\selectfont
      \begin{minted}{text}
# modprobe g_serial
# cat /dev/ttyGS0 > /dev/ttyGS0
      \end{minted}
    \end{block}
    \item On the host
    \begin{itemize}
      \item Open and play with the TTY (picocom)
    \end{itemize}
    \begin{block}{}
      \fontsize{8}{8}\selectfont
      \begin{minted}{text}
# picocom -b115200 /dev/ttyACM0
      \end{minted}
    \end{block}
  \end{itemize}
\end{frame}

\questionslide

\subsection{Extra slides}

\begin{frame}{Data transfers, IN queue processing (from device to host)}
  \begin{center}
    \includegraphics[width=0.7\textwidth]{graphics/process-in.pdf}
  \end{center}
\end{frame}

\begin{frame}{Data transfers, OUT queue processing (from host to device)}
  \begin{center}
    \includegraphics[width=0.45\textwidth]{graphics/process-out.pdf}
  \end{center}
\end{frame}

\begin{frame}{EP0 handling}
  \begin{center}
    \includegraphics[width=1.0\textwidth]{graphics/process-ep0.pdf}
  \end{center}
\end{frame}

%\begin{frame}{EP0 handling, Received SETUP}
%  \begin{center}
%    \includegraphics[width=1.0\textwidth]{graphics/process-ep0-start.pdf}
%  \end{center}
%\end{frame}
%
%\begin{frame}{EP0 handling, Handle at UDC level}
%  \begin{center}
%    \includegraphics[width=0.6\textwidth]{graphics/process-ep0-udc.pdf}
%  \end{center}
%\end{frame}
%
%\begin{frame}{EP0 handling, Delegate to Core}
%  \begin{center}
%    \includegraphics[width=0.8\textwidth]{graphics/process-ep0-core.pdf}
%  \end{center}
%\end{frame}

\end{document}
