\input{configpres} \title{struct device} %\maketitle \begin{frame} \maketitle{aim} \begin{itemize} \item lowest level representation of every device in a Linux system \item hosts information that the device model core needs to model the system \item most subsystems track additional information about the devices they host \item it is rare for devices to be represented by bare device structures \item this struct is usually embedded within higher-level representation of the device \end{itemize} \end{frame} \subtitle{components of the struct} \begin{frame} \frametitle{name and type} for example a mouse device \begin{tiny} \begin{lstlisting}[frame=trBL] include/linux/device.h: ... struct device { ... const char *init_name; const struct device_type *type; ... \end{lstlisting} \end{tiny} \end{frame} \begin{frame} \frametitle{connection of multiple devices} for example usb-hostcontroller1/usb-device3/usb-endpoint4/mouse \begin{tiny} \begin{lstlisting}[frame=trBL] include/linux/device.h: ... struct device { ... struct device *parent; ... \end{lstlisting} \end{tiny} \begin{itemize} \item 'parent' is a ptr to the device to which this device is attached \item normaly a parent device is some sort of bus or host controller \item If parent is NULL, the device, is a top-level device, which is not usually what you want \end{itemize} \end{frame} \begin{frame} \frametitle{private data} \begin{tiny} \begin{lstlisting}[frame=trBL] drivers/base/base.h ... struct device_private { struct klist klist_children; //containing all children of this device struct klist_node knode_parent; //node in sibling list struct klist_node knode_driver; //node in driver list struct klist_node knode_bus; //node in bus list struct list_head deferred_probe;//entry in deferred_probe_list void *driver_data; //private pointer for driver specific info struct device *device; //pointer back to the device }; ... include/linux/device.h: ... struct device { ... struct device_private *p; ... \end{lstlisting} \end{tiny} \end{frame} \begin{frame} \frametitle{bus} \begin{tiny} \begin{lstlisting}[frame=trBL] include/linux/device.h: ... struct device { ... struct bus_type *bus; ... \end{lstlisting} \end{tiny} \begin{itemize} \item used by driver core to link between bus - device \item hosts pointer for: probe, remove, suspend, \dots \item these functions are called by the driver core on bus state changes \item bus drivers need to implement these calls and normaly redirect them to the associated devices \end{itemize} \end{frame} \begin{frame} \frametitle{driver} \begin{tiny} \begin{lstlisting}[frame=trBL] include/linux/device.h: ... struct device { ... struct device_driver *driver; ... \end{lstlisting} \end{tiny} \begin{itemize} \item used by driver core to link between driver - device \item hosts a table of device id, the driver is responsible for \item hosts pointer for: probe, remove, suspend, \dots \item these functions are called by the bus driver on bus state changes \item device drivers need to implement these calls \item e.g. after a succesful probe call a driver is responsible for a device \end{itemize} \end{frame} \begin{frame} \frametitle{platform data} \begin{tiny} \begin{lstlisting}[frame=trBL] include/linux/device.h: ... struct device { ... void *platform_data; ... \end{lstlisting} \end{tiny} \begin{itemize} \item structure is declared by the platform device driver \item structure is normally initialized by 'board support package' \item hosts for example how a specific device is connected (mem\_base, irq) \item can host informations about chip variants \item shrinks 'board support packages' \item reduces board specific #ifdefs in driver code \end{itemize} \end{frame} \begin{frame} \frametitle{misc} \begin{itemize} \item structs for device power management \item ptr to NUMA node this device is close to \item structs for DMA handling (if device is DMA capable) \item information about associated device node(s) (/dev/huhu) \item unique device id \item lock to protect device resources \item pointer to release() function of the device \end{itemize} \end{frame} \subtitle{how is it used} \begin{frame} \frametitle{initialization} The bus driver that discovers the device uses this to register the device with the core: \begin{tiny} \begin{lstlisting}[frame=trBL] int device_register(struct device * dev); \end{lstlisting} \end{tiny} these fields should be initialized before calling the register function: \begin{itemize} \item parent \item name \item bus\_id \item bus \end{itemize} \end{frame} \begin{frame} \frametitle{use by a driver} A device is removed from the core when its reference count goes to 0. The reference count can be adjusted using: \begin{tiny} \begin{lstlisting}[frame=trBL] struct device * get_device(struct device * dev); void put_device(struct device * dev); \end{lstlisting} \end{tiny} The device lock can be accessed by: \begin{tiny} \begin{lstlisting}[frame=trBL] void lock_device(struct device * dev); void unlock_device(struct device * dev); \end{lstlisting} \end{tiny} \end{frame} \begin{frame} \frametitle{device attributes} Attributes can be exported to sysfs by the device driver. \begin{tiny} \begin{lstlisting}[frame=trBL] my.c: ... static DEVICE_ATTR(ro, 0444, my_show_ro, NULL); static DEVICE_ATTR(rw, 0644, my_show_rw, my_store_rw); static struct attribute *my_dev_attrs[] = { &dev_attr_ro.attr, &dev_attr_rw.attr, NULL, }; static struct attribute_group my_dev_attr_group = { .attrs = my_dev_attrs, }; static const struct attribute_group *my_dev_attr_groups[] = { &my_dev_attr_group, NULL, }; static int __init my_driver_init(struct device *my_dev) { ... my_dev->groups = my_dev_attr_groups; device_register(my_dev); ... } \end{lstlisting} \end{tiny} \end{frame} \input{tailpres}