\subsection{Kernel Architecture for Device Drivers}

\begin{frame}
  \frametitle{Kernel and Device Drivers}
  \begin{center}
    \includegraphics[height=0.8\textheight]{slides/kernel-driver-development-architecture-drivers/driver-architecture.pdf}
  \end{center}
\end{frame}

\begin{frame}
  \frametitle{Kernel and Device Drivers}
  \begin{itemize}
  \item Many device drivers are not implemented directly as character
    drivers
  \item They are implemented under a \emph{framework}, specific to a
    given device type (framebuffer, V4L, serial, etc.)
    \begin{itemize}
    \item The framework allows to factorize the common parts of
      drivers for the same type of devices
    \item From userspace, they are still seen as character devices by
      the applications
    \item The framework allows to provide a coherent userspace
      interface (\code{ioctl}, etc.) for every type of device,
      regardless of the driver
    \end{itemize}
  \item The device drivers rely on the \emph{bus infrastructure} to
    enumerate the devices and communicate with them.
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Kernel Frameworks}
  \begin{center}
    \includegraphics[width=\textwidth]{slides/kernel-driver-development-architecture-drivers/frameworks.pdf}
  \end{center}
\end{frame}

\begin{frame}
  \frametitle{Example: Framebuffer Framework}
  \begin{itemize}
  \item Kernel option \code{CONFIG_FB}
    \begin{itemize}
    \item \code{menuconfig FB}
      \begin{itemize}
      \item \code{tristate "Support for frame buffer devices"}
      \end{itemize}
    \end{itemize}
  \item Implemented in \code{drivers/video/}
    \begin{itemize}
    \item \code{fb.c}, \code{fbmem.c}, \code{fbmon.c},
      \code{fbcmap.c}, \code{fbsysfs.c}, \code{modedb.c},
      \code{fbcvt.c}
    \end{itemize}
  \item Implements a single character driver and defines the
    user/kernel API
    \begin{itemize}
    \item First part of \code{include/linux/fb.h}
    \end{itemize}
  \item Defines the set of operations a framebuffer driver must
    implement and helper functions for the drivers
    \begin{itemize}
    \item \code{struct fb_ops}
    \item Second part of \code{include/linux/fb.h} (in
      \code{ifdef __KERNEL__})
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Framebuffer Driver Skeleton}
  \begin{itemize}
  \item Skeleton driver in \code{drivers/video/skeletonfb.c}
  \item Implements the set of framebuffer specific operations defined
    by the \code{struct fb_ops} structure
  \end{itemize}
  \begin{columns}
    \column{0.45\textwidth}
    \begin{itemize}
    \item \code{xxxfb_open()}
    \item \code{xxxfb_read()}
    \item \code{xxxfb_write()}
    \item \code{xxxfb_release()}
    \item \code{xxxfb_checkvar()}
    \item \code{xxxfb_setpar()}
    \item \code{xxxfb_setcolreg()}
    \item \code{xxxfb_blank()}
    \item \code{xxxfb_pan_display()}
    \end{itemize}
    \column{0.45\textwidth}
    \begin{itemize}
    \item \code{xxxfb_fillrect()}
    \item \code{xxxfb_copyarea()}
    \item \code{xxxfb_imageblit()}
    \item \code{xxxfb_cursor()}
    \item \code{xxxfb_rotate()}
    \item \code{xxxfb_sync()}
    \item \code{xxxfb_ioctl()}
    \item \code{xxxfb_mmap()}
    \end{itemize}
  \end{columns}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Framebuffer Driver Skeleton}
  \begin{itemize}
  \item After the implementation of the operations, definition of a
    \code{struct fb_ops} structure
  \begin{minted}[fontsize=\scriptsize]{c}
static struct fb_ops xxxfb_ops = {
    .owner = THIS_MODULE,
    .fb_open = xxxfb_open,
    .fb_read = xxxfb_read,
    .fb_write = xxxfb_write,
    .fb_release = xxxfb_release,
    .fb_check_var = xxxfb_check_var,
    .fb_set_par = xxxfb_set_par,
    .fb_setcolreg = xxxfb_setcolreg,
    .fb_blank = xxxfb_blank,
    .fb_pan_display = xxxfb_pan_display,
    .fb_fillrect = xxxfb_fillrect,   /* Needed !!! */
    .fb_copyarea = xxxfb_copyarea,   /* Needed !!! */
    .fb_imageblit = xxxfb_imageblit, /* Needed !!! */
    .fb_cursor = xxxfb_cursor,       /* Optional !!! */
    .fb_rotate = xxxfb_rotate,
    .fb_sync = xxxfb_sync,
    .fb_ioctl = xxxfb_ioctl,
    .fb_mmap = xxxfb_mmap,
};
  \end{minted}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Framebuffer Driver Skeleton}
  \begin{itemize}
  \item In the \code{probe()} function, registration of the
    framebuffer device and operations
  \begin{minted}[fontsize=\footnotesize]{c}
static int __devinit xxxfb_probe (struct pci_dev *dev,
    const struct pci_device_id *ent)
{
    struct fb_info *info;
    [...]
    info = framebuffer_alloc(sizeof(struct xxx_par), device);
    [...]
    info->fbops = &xxxfb_ops;
    [...]
    if (register_framebuffer(info) > 0)
        return -EINVAL;
    [...]
}
  \end{minted}
  \item \code{register_framebuffer()} will create the character device
    that can be used by userspace applications with the generic
    framebuffer API.
\end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Unified Device Model}
  \begin{itemize}
  \item The 2.6 kernel included a significant new feature: a unified
    device model
  \item Instead of having different ad-hoc mechanisms in the various
    subsystems, the device model unifies the description of the
    devices and their topology
    \begin{itemize}
    \item Minimization of code duplication
    \item Common facilities (reference counting, event notification,
      power management, etc.)
    \item Enumerate the devices view their interconnections, link the
      devices to their buses and drivers, etc.
    \end{itemize}
  \item Understanding the device model is necessary to understand how
    device drivers fit into the Linux kernel architecture.
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Bus Drivers}
  \begin{itemize}
  \item The first component of the device model is the bus driver
    \begin{itemize}
    \item One bus driver for each type of bus: USB, PCI, SPI, MMC,
      I2C, etc.
    \end{itemize}
  \item It is responsible for
    \begin{itemize}
    \item Registering the bus type (\code{struct bus_type})
    \item Allowing the registration of adapter drivers (USB
      controllers, I2C adapters, etc.), able of detecting the
      connected devices, and providing a communication mechanism with
      the devices
    \item Allowing the registration of device drivers (USB devices,
      I2C devices, PCI devices, etc.), managing the devices
    \item Matching the device drivers against the devices detected by
      the adapter drivers.
    \item Provides an API to both adapter drivers and device drivers
    \item Defining driver and device specific structure, typically
      \code{xxx_driver} and \code{xxx_device}
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}
\frametitle{Example: USB Bus 1/2}
  \begin{center}
    \includegraphics[width=\textwidth]{slides/kernel-driver-development-architecture-drivers/usb-bus.pdf}
  \end{center}
\end{frame}

\begin{frame}
  \frametitle{Example: USB Bus 2/2}
  \begin{itemize}
  \item Core infrastructure (bus driver)
    \begin{itemize}
    \item \code{drivers/usb/core}
    \item The \code{bus_type} is defined in
      \code{drivers/usb/core/driver.c} and registered in
      \code{drivers/usb/core/usb.c}
    \end{itemize}
  \item Adapter drivers
    \begin{itemize}
    \item \code{drivers/usb/host}
    \item For EHCI, UHCI, OHCI, XHCI, and their implementations on
      various systems (Atmel, IXP, Xilinx, OMAP, Samsung, PXA, etc.)
    \end{itemize}
  \item Device drivers
    \begin{itemize}
    \item Everywhere in the kernel tree, classified by their type
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Example of Device Driver}
  \begin{itemize}
  \item To illustrate how drivers are implemented to work with the
    device model, we will study the source code of a driver for a USB
    network card
    \begin{itemize}
    \item It is USB device, so it has to be a USB device driver
    \item It is a network device, so it has to be a network device
    \item Most drivers rely on a bus infrastructure (here, USB) and
      register themselves in a framework (here, network)
    \end{itemize}
  \item We will only look at the device driver side, and not the
    adapter driver side
  \item The driver we will look at is \code{drivers/net/usb/rtl8150.c}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Device Identifiers}
  \begin{itemize}
  \item Defines the set of devices that this driver can manage, so
    that the USB core knows for which devices this driver should be
    used
  \item The \code{MODULE_DEVICE_TABLE} macro allows \code{depmod} to
    extract at compile time the relation between device identifiers
    and drivers, so that drivers can be loaded automatically by
    udev. See \code{/lib/modules/$(uname -r)/modules.{alias,usbmap}}
  \end{itemize}
  \begin{minted}[fontsize=\footnotesize]{c}
static struct usb_device_id rtl8150_table[] = {
    { USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150) },
    { USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX) },
    { USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR) },
    { USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX) },
    { USB_DEVICE(VENDOR_ID_OQO, PRODUCT_ID_RTL8150) },
    { USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE) },
    {}
};
MODULE_DEVICE_TABLE(usb, rtl8150_table);
  \end{minted}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Instantiation of usb\_driver}
  \begin{itemize}
  \item \code{struct usb_driver} is a structure defined by the USB
    core. Each USB device driver must instantiate it, and register
    itself to the USB core using this structure
  \item This structure inherits from struct driver, which is defined
    by the device model.
  \begin{minted}{c}
static struct usb_driver rtl8150_driver = {
    .name = "rtl8150",
    .probe = rtl8150_probe,
    .disconnect = rtl8150_disconnect,
    .id_table = rtl8150_table,
    .suspend = rtl8150_suspend,
    .resume = rtl8150_resume
};
  \end{minted}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Driver (Un)Registration}
  \begin{itemize}
  \item When the driver is loaded or unloaded, it must register or
    unregister itself from the USB core
  \item Done using \code{usb_register()} and \code{usb_deregister()},
    provided by the USB core.
\begin{minted}[fontsize=\footnotesize]{c}
static int __init usb_rtl8150_init(void)
{
    return usb_register(&rtl8150_driver);
}

static void __exit usb_rtl8150_exit(void)
{
    usb_deregister(&rtl8150_driver);
}

module_init(usb_rtl8150_init);
module_exit(usb_rtl8150_exit);
\end{minted}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{At Initialization}
  \begin{itemize}
  \item The USB adapter driver that corresponds to the USB controller
    of the system registers itself to the USB core
  \item The rtl8150 USB device driver registers itself to the USB core
    \begin{center}
      \includegraphics[height=0.4\textheight]{slides/kernel-driver-development-architecture-drivers/usb-registering.pdf}
    \end{center}
  \item The USB core now knows the association between the
    vendor/product IDs of rtl8150 and the \code{usb_driver} structure
    of this driver
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{When a Device is Detected}
  \begin{center}
    \includegraphics[width=\textwidth]{slides/kernel-driver-development-architecture-drivers/usb-detection.pdf}
  \end{center}
\end{frame}

\begin{frame}
  \frametitle{Probe Method}
  \begin{itemize}
  \item The \code{probe()} method receives as argument a structure
    describing the device, usually specialized by the bus
    infrastructure (\code{pci_dev}, \code{usb_interface}, etc.)
  \item This function is responsible for
    \begin{itemize}
    \item Initializing the device, mapping I/O memory, registering the
      interrupt handlers. The bus infrastructure provides methods to
      get the addresses, interrupt numbers and other device-specific
      information.
    \item Registering the device to the proper kernel framework, for
      example the network infrastructure.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
\frametitle{Probe Method Example}
\begin{minted}[fontsize=\scriptsize]{c}
static int rtl8150_probe(struct usb_interface *intf,
    const struct usb_device_id *id)
{
    rtl8150_t *dev;
    struct net_device *netdev;

    netdev = alloc_etherdev(sizeof(rtl8150_t));
    [...]
    dev = netdev_priv(netdev);
    tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev);
    spin_lock_init(&dev->rx_pool_lock);
    [...]
    netdev->netdev_ops = &rtl8150_netdev_ops;
    alloc_all_urbs(dev);
    [...]
    usb_set_intfdata(intf, dev);
    SET_NETDEV_DEV(netdev, &intf->dev);
    register_netdev(netdev);

    return 0;
}
\end{minted}
\end{frame}

\begin{frame}
  \frametitle{The Model is Recursive}
  \begin{center}
    \includegraphics[width=\textwidth]{slides/kernel-driver-development-architecture-drivers/recursive-model.pdf}
  \end{center}
\end{frame}

\begin{frame}
  \frametitle{sysfs}
  \begin{itemize}
  \item The bus, device, drivers, etc. structures are internal to the
    kernel
  \item The \code{sysfs} virtual filesystem offers a mechanism to
    export such information to userspace
  \item Used for example by udev to provide automatic module loading,
    firmware loading, device file creation, etc.
  \item \code{sysfs} is usually mounted in /sys
    \begin{itemize}
    \item \code{/sys/bus/} contains the list of buses
    \item \code{/sys/devices/} contains the list of devices
    \item \code{/sys/class} enumerates devices by class (net, input,
      block...), whatever the bus they are connected to. Very useful!
    \end{itemize}
  \item Take your time to explore \code{/sys} on your workstation.
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Platform Devices}
  \begin{itemize}
  \item On embedded systems, devices are often not connected through a
    bus allowing enumeration, hotplugging, and providing unique
    identifiers for devices.
  \item However, we still want the devices to be part of the device
    model.
  \item The solution to this is the \emph{platform driver} /
    \emph{platform device} infrastructure.
  \item The platform devices are the devices that are directly
    connected to the CPU, without any kind of bus.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Implementation of the Platform Driver}
  \begin{itemize}
  \item The driver implements a \code{struct platform_driver}
    structure (example taken from \code{drivers/serial/imx.c})
    \begin{minted}[fontsize=\footnotesize]{c}
static struct platform_driver serial_imx_driver = {
    .probe = serial_imx_probe,
    .remove = serial_imx_remove,
    .driver = {
        .name = "imx-uart",
        .owner = THIS_MODULE,
    },
};
    \end{minted}
\item And registers its driver to the platform driver infrastructure
  \begin{minted}[fontsize=\footnotesize]{c}
static int __init imx_serial_init(void) {
    ret = platform_driver_register(&serial_imx_driver);
}

static void __exit imx_serial_cleanup(void) {
    platform_driver_unregister(&serial_imx_driver);
}
  \end{minted}
\end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Platform Device Instantiation 1/2}
  \begin{itemize}
  \item As platform devices cannot be detected dynamically, they are
    defined statically
    \begin{itemize}
    \item By direct instantiation of \code{struct platform_device}
      structures, as done on some ARM platforms. Definition done in
      the board-specific or SoC specific code.
    \item By using a \emph{device tree}, as done on Power PC (and on
      some ARM platforms) from which \code{struct platform_device}
      structures are created
    \end{itemize}
  \item Example on ARM, where the instantiation is done in
    \code{arch/arm/mach-imx/mx1ads.c}
\begin{minted}[fontsize=\footnotesize]{c}
static struct platform_device imx_uart1_device = {
    .name = "imx-uart",
    .id = 0,
    .num_resources = ARRAY_SIZE(imx_uart1_resources),
    .resource = imx_uart1_resources,
    .dev = {
         .platform_data = &uart_pdata,
    }
};
\end{minted}
\end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Platform device instantiation 2/2}
  \begin{itemize}
  \item The device is part of a list
  \begin{minted}[fontsize=\footnotesize]{c}
static struct platform_device *devices[] __initdata = {
    &cs89x0_device,
    &imx_uart1_device,
    &imx_uart2_device,
};
  \end{minted}
  \item And the list of devices is added to the system during
    board initialization
  \begin{minted}[fontsize=\footnotesize]{c}
static void __init mx1ads_init(void)
{
    [...]
    platform_add_devices(devices, ARRAY_SIZE(devices));
}

MACHINE_START(MX1ADS, "Freescale MX1ADS")
    [...]
    .init_machine = mx1ads_init,
MACHINE_END
  \end{minted}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{The Resource Mechanism}
  \begin{itemize}
  \item Each device managed by a particular driver typically uses
    different hardware resources: addresses for the I/O registers, DMA
    channels, IRQ lines, etc.
  \item Such information can be represented using the
    \code{struct resource}, and an array of \code{struct resource} is
    associated to a \code{platform_device}
  \item Allows a driver to be instantiated for multiple devices
    functioning similarly, but with different addresses, IRQs, etc.
  \end{itemize}
  \begin{minted}[fontsize=\scriptsize]{c}
static struct resource imx_uart1_resources[] = {
    [0] = {
        .start = 0x00206000,
        .end = 0x002060FF,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = (UART1_MINT_RX),
        .end = (UART1_MINT_RX),
        .flags = IORESOURCE_IRQ,
    },
};
  \end{minted}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Using Resources}
  \begin{itemize}
  \item When a \code{platform_device} is added to the system using
    \code{platform_add_device()}, the \code{probe()} method of the
    platform driver gets called
  \item This method is responsible for initializing the hardware,
    registering the device to the proper framework (in our case, the
    serial driver framework)
  \item The platform driver has access to the I/O resources:
  \begin{minted}[fontsize=\footnotesize]{c}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = ioremap(res->start, PAGE_SIZE);
sport->rxirq = platform_get_irq(pdev, 0);
  \end{minted}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{platform\_data Mechanism}
  \begin{itemize}
  \item In addition to the well-defined resources, many drivers
    require driver-specific information for each platform device
  \item Such information can be passed using the \code{platform_data}
    field of the struct device (from which
    \code{struct platform_device} inherits)
  \item As it is a \code{void *} pointer, it can be used to pass any
    type of information.
    \begin{itemize}
    \item Typically, each driver defines a structure to pass
      information through \code{platform_data}
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{platform\_data example 1/2}
  \begin{itemize}
  \item The i.MX serial port driver defines the following structure to
    be passed through \code{platform_data}

  \begin{minted}[fontsize=\footnotesize]{c}
struct imxuart_platform_data {
    int (*init)(struct platform_device *pdev);
    void (*exit)(struct platform_device *pdev);
    unsigned int flags;
    void (*irda_enable)(int enable);
    unsigned int irda_inv_rx:1;
    unsigned int irda_inv_tx:1;
    unsigned short transceiver_delay;
};
  \end{minted}
  \item The MX1ADS board code instantiates such a structure
  \begin{minted}[fontsize=\footnotesize]{c}
static struct imxuart_platform_data uart1_pdata = {
    .flags = IMXUART_HAVE_RTSCTS,
};
  \end{minted}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{platform\_data Example 2/2}
  \begin{itemize}
  \item The \code{uart_pdata} structure is associated to the
    \code{platform_device} in the MX1ADS board file (the real code is
    slightly more complicated)
  \begin{minted}[fontsize=\scriptsize]{c}
struct platform_device mx1ads_uart1 = {
    .name = "imx-uart",
    .dev {
         .platform_data = &uart1_pdata,
    },
    .resource = imx_uart1_resources,
    [...]
};
  \end{minted}
  \item The driver can access the platform data:
  \begin{minted}[fontsize=\scriptsize]{c}
static int serial_imx_probe(struct platform_device *pdev)
{
    struct imxuart_platform_data *pdata;
    pdata = pdev->dev.platform_data;
    if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
        sport->have_rtscts = 1;
    [...]
}
  \end{minted}
\end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Driver-specific Data Structure}
  \begin{itemize}
  \item Each \emph{framework} defines a structure that a device driver
    must register to be recognized as a device in this framework
    \begin{itemize}
    \item \code{uart_port} for serial port, \code{netdev} for network
      devices, \code{fb_info} for framebuffers, etc.
    \end{itemize}
  \item In addition to this structure, the driver usually needs to
    store additional information about its device
  \item This is typically done
    \begin{itemize}
    \item By subclassing the appropriate framework structure
    \item Or by storing a reference to the appropriate framework
      structure
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Driver-specific Data Structure Examples}
  \begin{itemize}
  \item i.MX serial driver: \code{imx_port} is a subclass of
    \code{uart_port}
  \begin{minted}[fontsize=\scriptsize]{c}
struct imx_port {
    struct uart_port port;
    struct timer_list timer;
    unsigned int old_status;
    int txirq, rxirq, rtsirq;
    unsigned int have_rtscts:1;
    [...]
};
  \end{minted}
  \item rtl8150 network driver: \code{rtl8150} has a reference to
    \code{net_device}
  \begin{minted}[fontsize=\scriptsize]{c}
struct rtl8150 {
    unsigned long flags;
    struct usb_device *udev;
    struct tasklet_struct tl;
    struct net_device *netdev;
    [...]
};
  \end{minted}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Link Between Structures 1/3}
  \begin{itemize}
  \item The framework typically contains a \code{struct device *}
    pointer that the driver must point to the corresponding struct
    device
    \begin{itemize}
    \item It's the relation between the logical device (for example a
      network interface) and the physical device (for example the USB
      network adapter)
    \end{itemize}
  \item The device structure also contains a \code{void *} pointer
    that the driver can freely use.
    \begin{itemize}
    \item It's often use to link back the device to the higher-level
      structure from the framework.
    \item It allows, for example, from the \code{platform_device}
      structure, to find the structure describing the logical device
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Link Between Structures 2/3}
  \begin{columns}
    \column{0.7\textwidth}
    \begin{minted}[fontsize=\tiny]{c}
static int serial_imx_probe(struct platform_device *pdev)
{
    struct imx_port *sport;
    [...]
    /* setup the link between uart_port and the struct
     * device inside the platform_device */
    sport->port.dev = &pdev->dev;
    [...]
    /* setup the link between the struct device inside
     * the platform device to the imx_port structure */
    platform_set_drvdata(pdev, &sport->port);
    [...]
    uart_add_one_port(&imx_reg, &sport->port);
}

static int serial_imx_remove(struct platform_device *pdev)
{
    /* retrieve the imx_port from the platform_device */
    struct imx_port *sport = platform_get_drvdata(pdev);
    [...]
    uart_remove_one_port(&imx_reg, &sport->port);
    [...]
}
    \end{minted}
    \column{0.3\textwidth}
    \begin{center}
      \includegraphics[width=\textwidth]{slides/kernel-driver-development-architecture-drivers/link-structures-imx.pdf}
    \end{center}
  \end{columns}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Link Between Structures 3/3}
  \begin{columns}
    \column{0.7\textwidth}
    \begin{minted}[fontsize=\tiny]{c}
static int rtl8150_probe(struct usb_interface *intf,
    const struct usb_device_id *id)
{
    rtl8150_t *dev;
    struct net_device *netdev;

    netdev = alloc_etherdev(sizeof(rtl8150_t));
    dev = netdev_priv(netdev);

    usb_set_intfdata(intf, dev);
    SET_NETDEV_DEV(netdev, &intf->dev);

    [...]
}

static void rtl8150_disconnect(struct usb_interface *intf)
{
    rtl8150_t *dev = usb_get_intfdata(intf);

    [...]
}
    \end{minted}
    \column{0.3\textwidth}
    \begin{center}
      \includegraphics[height=0.8\textheight]{slides/kernel-driver-development-architecture-drivers/link-structures-netdev.pdf}
    \end{center}
  \end{columns}
\end{frame}

\begin{frame}
  \frametitle{Example of Another Non-Dynamic Bus: SPI}
  \begin{itemize}
  \item SPI is called non-dynamic as it doesn't support runtime
    enumeration of devices: the system needs to know which devices are
    on which SPI bus, and at which location
  \item The SPI infrastructure in the kernel is in \code{drivers/spi}
    \begin{itemize}
    \item \code{drivers/spi/spi.c} is the core, which implements the
      \code{struct bus_type} for spi
      \begin{itemize}
      \item It allows registration of adapter drivers using
        \code{spi_register_master()}, and registration of device
        drivers using \code{spi_register_driver()}
      \end{itemize}
    \item \code{drivers/spi/} contains many adapter drivers, for
      various platforms: Atmel, OMAP, Xilinx, Samsung, etc.
      \begin{itemize}
      \item Most of them are \code{platform_drivers} or
        \code{of_platform_drivers}, \code{one pci_driver}, one
        \code{amba_driver}, one \code{partport_driver}
      \end{itemize}
    \item \code{drivers/spi/spidev.c} provides an infrastructure to
      access SPI bus from userspace
    \item SPI device drivers are present all over the kernel tree
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{SPI Components}
  \begin{center}
    \includegraphics[width=\textwidth]{slides/kernel-driver-development-architecture-drivers/spi-components.pdf}
  \end{center}
\end{frame}

\begin{frame}[fragile]
  \frametitle{SPI AT91 SoC Code: at91sam9260\_devices 1/2}
  \begin{minted}[fontsize=\scriptsize]{c}
static struct resource spi0_resources[] = {
    [0] = {
         .start = AT91SAM9260_BASE_SPI0,
         .end = AT91SAM9260_BASE_SPI0 + SZ_16K - 1,
         .flags = IORESOURCE_MEM,
    },
    [1] = {
         .start = AT91SAM9260_ID_SPI0,
         .end = AT91SAM9260_ID_SPI0,
         .flags = IORESOURCE_IRQ,
    },
};

static struct platform_device at91sam9260_spi0_device = {
    .name = "atmel_spi",
    .id = 0,
    .dev = {
        .dma_mask = &spi_dmamask,
        .coherent_dma_mask = DMA_BIT_MASK(32),
    },
    .resource = spi0_resources,
    .num_resources = ARRAY_SIZE(spi0_resources),
};
  \end{minted}
\end{frame}

\begin{frame}[fragile]
  \frametitle{SPI AT91 SoC Code: at91sam9260\_devices 2/2}
  \begin{itemize}
  \item Registration of SPI devices with
    \code{spi_register_board_info()}, registration of SPI adapter with
    \code{platform_device_register()}
  \begin{minted}[fontsize=\scriptsize]{c}
void __init at91_add_device_spi(struct spi_board_info *devices,
    int nr_devices)
{
    [...]
    spi_register_board_info(devices, nr_devices);

    /* Configure SPI bus(es) */
    if (enable_spi0) {
        at91_set_A_periph(AT91_PIN_PA0, 0); /* SPI0_MISO */
        at91_set_A_periph(AT91_PIN_PA1, 0); /* SPI0_MOSI */
        at91_set_A_periph(AT91_PIN_PA2, 0); /* SPI1_SPCK */

        at91_clock_associate("spi0_clk", &at91sam9260_spi0_device.dev,
                             "spi_clk");
        platform_device_register(&at91sam9260_spi0_device);
    }

    [...]
}
  \end{minted}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{AT91RM9200DK Board Code for SPI}
  \begin{itemize}
  \item One \code{spi_board_info} structure for each SPI device
    connected to the system.
  \begin{minted}[fontsize=\tiny]{c}
static struct spi_board_info dk_spi_devices[] = {
    {
        /* DataFlash chip */
        .modalias = "mtd_dataflash",
        .chip_select = 0,
        .max_speed_hz = 15 * 1000 * 1000,
    },
    {
        /* UR6HCPS2-SP40 PS2-to-SPI adapter */
        .modalias = "ur6hcps2",
        .chip_select = 1,
        .max_speed_hz = 250 * 1000,
    },
    [...]
};

static void __init dk_board_init(void)
{
    [...]
    at91_add_device_spi(dk_spi_devices, ARRAY_SIZE(dk_spi_devices));
    [..]
}
  \end{minted}
  \item Taken from \code{arch/arm/mach-at91/board-dk.c}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{References}
  \begin{itemize}
  \item Kernel documentation
    \begin{itemize}
    \item \code{Documentation/driver-model/}
    \item \code{Documentation/filesystems/sysfs.txt}
    \end{itemize}
  \item The kernel source code
    \begin{itemize}
    \item Full of examples of other drivers!
    \end{itemize}
  \end{itemize}
\end{frame}

