summaryrefslogtreecommitdiff
path: root/kernel-devel/linux-device/pres_linux-device_en.tex
blob: c234b360e14f7f9eed86b746f87847d9301dae4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
\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
\item class
\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_example, 0444, my_show_ro, NULL);
static DEVICE_ATTR(rw_example, 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}