-
Notifications
You must be signed in to change notification settings - Fork 1
/
device_if.h
402 lines (371 loc) · 11.9 KB
/
device_if.h
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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
/*
* This file is @generated automatically.
* Do not modify anything in here by hand.
*
* Created from source file
* /usr/src/sys/kern/device_if.m
* with
* makeobjops.awk
*
* See the source file for legal information
*/
/**
* @defgroup DEVICE device - KObj methods for all device drivers
* @brief A basic set of methods required for all device drivers.
*
* The device interface is used to match devices to drivers during
* autoconfiguration and provides methods to allow drivers to handle
* system-wide events such as suspend, resume or shutdown.
* @{
*/
#ifndef _device_if_h_
#define _device_if_h_
#include <sys/tslog.h>
/** @brief Unique descriptor for the DEVICE_PROBE() method */
extern struct kobjop_desc device_probe_desc;
/** @brief A function implementing the DEVICE_PROBE() method */
typedef int device_probe_t(device_t dev);
/**
* @brief Probe to see if a device matches a driver.
*
* Users should not call this method directly. Normally, this
* is called via device_probe_and_attach() to select a driver
* calling the DEVICE_PROBE() of all candidate drivers and attach
* the winning driver (if any) to the device.
*
* This function is used to match devices to device drivers.
* Typically, the driver will examine the device to see if
* it is suitable for this driver. This might include checking
* the values of various device instance variables or reading
* hardware registers.
*
* In some cases, there may be more than one driver available
* which can be used for a device (for instance there might
* be a generic driver which works for a set of many types of
* device and a more specific driver which works for a subset
* of devices). Because of this, a driver should not assume
* that it will be the driver that attaches to the device even
* if it returns a success status from DEVICE_PROBE(). In particular,
* a driver must free any resources which it allocated during
* the probe before returning. The return value of DEVICE_PROBE()
* is used to elect which driver is used - the driver which returns
* the largest non-error value wins the election and attaches to
* the device. Common non-error values are described in the
* DEVICE_PROBE(9) manual page.
*
* If a driver matches the hardware, it should set the device
* description string using device_set_desc() or
* device_set_desc_copy(). This string is used to generate an
* informative message when DEVICE_ATTACH() is called.
*
* As a special case, if a driver returns zero, the driver election
* is cut short and that driver will attach to the device
* immediately. This should rarely be used.
*
* For example, a probe method for a PCI device driver might look
* like this:
*
* @code
* int
* foo_probe(device_t dev)
* {
* if (pci_get_vendor(dev) == FOOVENDOR &&
* pci_get_device(dev) == FOODEVICE) {
* device_set_desc(dev, "Foo device");
* return (BUS_PROBE_DEFAULT);
* }
* return (ENXIO);
* }
* @endcode
*
* To include this method in a device driver, use a line like this
* in the driver's method list:
*
* @code
* KOBJMETHOD(device_probe, foo_probe)
* @endcode
*
* @param dev the device to probe
*
* @retval 0 if this is the only possible driver for this
* device
* @retval negative if the driver can match this device - the
* least negative value is used to select the
* driver
* @retval ENXIO if the driver does not match the device
* @retval positive if some kind of error was detected during
* the probe, a regular unix error code should
* be returned to indicate the type of error
* @see DEVICE_ATTACH(), pci_get_vendor(), pci_get_device()
*/
static __inline int DEVICE_PROBE(device_t dev)
{
kobjop_t _m;
int rc;
TSENTER2(device_get_name(dev));
KOBJOPLOOKUP(((kobj_t)dev)->ops,device_probe);
rc = ((device_probe_t *) _m)(dev);
TSEXIT2(device_get_name(dev));
return (rc);
}
/** @brief Unique descriptor for the DEVICE_IDENTIFY() method */
extern struct kobjop_desc device_identify_desc;
/** @brief A function implementing the DEVICE_IDENTIFY() method */
typedef void device_identify_t(driver_t *driver, device_t parent);
/**
* @brief Allow a device driver to detect devices not otherwise enumerated.
*
* The DEVICE_IDENTIFY() method is used by some drivers (e.g. the ISA
* bus driver) to help populate the bus device with a useful set of
* child devices, normally by calling the BUS_ADD_CHILD() method of
* the parent device. For instance, the ISA bus driver uses several
* special drivers, including the isahint driver and the pnp driver to
* create child devices based on configuration hints and PnP bus
* probes respectively.
*
* Many bus drivers which support true plug-and-play do not need to
* use this method at all since child devices can be discovered
* automatically without help from child drivers.
*
* To include this method in a device driver, use a line like this
* in the driver's method list:
*
* @code
* KOBJMETHOD(device_identify, foo_identify)
* @endcode
*
* @param driver the driver whose identify method is being called
* @param parent the parent device to use when adding new children
*/
static __inline void DEVICE_IDENTIFY(driver_t *driver, device_t parent)
{
kobjop_t _m;
KOBJOPLOOKUP(driver->ops,device_identify);
((device_identify_t *) _m)(driver, parent);
}
/** @brief Unique descriptor for the DEVICE_ATTACH() method */
extern struct kobjop_desc device_attach_desc;
/** @brief A function implementing the DEVICE_ATTACH() method */
typedef int device_attach_t(device_t dev);
/**
* @brief Attach a device to a device driver
*
* Normally only called via device_probe_and_attach(), this is called
* when a driver has succeeded in probing against a device.
* This method should initialise the hardware and allocate other
* system resources (e.g. devfs entries) as required.
*
* To include this method in a device driver, use a line like this
* in the driver's method list:
*
* @code
* KOBJMETHOD(device_attach, foo_attach)
* @endcode
*
* @param dev the device to probe
*
* @retval 0 success
* @retval non-zero if some kind of error was detected during
* the attach, a regular unix error code should
* be returned to indicate the type of error
* @see DEVICE_PROBE()
*/
static __inline int DEVICE_ATTACH(device_t dev)
{
kobjop_t _m;
int rc;
TSENTER2(device_get_name(dev));
KOBJOPLOOKUP(((kobj_t)dev)->ops,device_attach);
rc = ((device_attach_t *) _m)(dev);
TSEXIT2(device_get_name(dev));
return (rc);
}
/** @brief Unique descriptor for the DEVICE_DETACH() method */
extern struct kobjop_desc device_detach_desc;
/** @brief A function implementing the DEVICE_DETACH() method */
typedef int device_detach_t(device_t dev);
/**
* @brief Detach a driver from a device.
*
* This can be called if the user is replacing the
* driver software or if a device is about to be physically removed
* from the system (e.g. for removable hardware such as USB or PCCARD).
*
* To include this method in a device driver, use a line like this
* in the driver's method list:
*
* @code
* KOBJMETHOD(device_detach, foo_detach)
* @endcode
*
* @param dev the device to detach
*
* @retval 0 success
* @retval non-zero the detach could not be performed, e.g. if the
* driver does not support detaching.
*
* @see DEVICE_ATTACH()
*/
static __inline int DEVICE_DETACH(device_t dev)
{
kobjop_t _m;
int rc;
KOBJOPLOOKUP(((kobj_t)dev)->ops,device_detach);
rc = ((device_detach_t *) _m)(dev);
return (rc);
}
/** @brief Unique descriptor for the DEVICE_SHUTDOWN() method */
extern struct kobjop_desc device_shutdown_desc;
/** @brief A function implementing the DEVICE_SHUTDOWN() method */
typedef int device_shutdown_t(device_t dev);
/**
* @brief Called during system shutdown.
*
* This method allows drivers to detect when the system is being shut down.
* Some drivers need to use this to place their hardware in a consistent
* state before rebooting the computer.
*
* To include this method in a device driver, use a line like this
* in the driver's method list:
*
* @code
* KOBJMETHOD(device_shutdown, foo_shutdown)
* @endcode
*/
static __inline int DEVICE_SHUTDOWN(device_t dev)
{
kobjop_t _m;
int rc;
KOBJOPLOOKUP(((kobj_t)dev)->ops,device_shutdown);
rc = ((device_shutdown_t *) _m)(dev);
return (rc);
}
/** @brief Unique descriptor for the DEVICE_SUSPEND() method */
extern struct kobjop_desc device_suspend_desc;
/** @brief A function implementing the DEVICE_SUSPEND() method */
typedef int device_suspend_t(device_t dev);
/**
* @brief This is called by the power-management subsystem when a
* suspend has been requested by the user or by some automatic
* mechanism.
*
* This gives drivers a chance to veto the suspend or save their
* configuration before power is removed.
*
* To include this method in a device driver, use a line like this in
* the driver's method list:
*
* @code
* KOBJMETHOD(device_suspend, foo_suspend)
* @endcode
*
* @param dev the device being suspended
*
* @retval 0 success
* @retval non-zero an error occurred while attempting to prepare the
* device for suspension
*
* @see DEVICE_RESUME()
*/
static __inline int DEVICE_SUSPEND(device_t dev)
{
kobjop_t _m;
int rc;
KOBJOPLOOKUP(((kobj_t)dev)->ops,device_suspend);
rc = ((device_suspend_t *) _m)(dev);
return (rc);
}
/** @brief Unique descriptor for the DEVICE_RESUME() method */
extern struct kobjop_desc device_resume_desc;
/** @brief A function implementing the DEVICE_RESUME() method */
typedef int device_resume_t(device_t dev);
/**
* @brief This is called when the system resumes after a suspend.
*
* To include this method in a device driver, use a line like this
* in the driver's method list:
*
* @code
* KOBJMETHOD(device_resume, foo_resume)
* @endcode
*
* @param dev the device being resumed
*
* @retval 0 success
* @retval non-zero an error occurred while attempting to restore the
* device from suspension
*
* @see DEVICE_SUSPEND()
*/
static __inline int DEVICE_RESUME(device_t dev)
{
kobjop_t _m;
int rc;
KOBJOPLOOKUP(((kobj_t)dev)->ops,device_resume);
rc = ((device_resume_t *) _m)(dev);
return (rc);
}
/** @brief Unique descriptor for the DEVICE_QUIESCE() method */
extern struct kobjop_desc device_quiesce_desc;
/** @brief A function implementing the DEVICE_QUIESCE() method */
typedef int device_quiesce_t(device_t dev);
/**
* @brief This is called when the driver is asked to quiesce itself.
*
* The driver should arrange for the orderly shutdown of this device.
* All further access to the device should be curtailed. Soon there
* will be a request to detach, but there won't necessarily be one.
*
* To include this method in a device driver, use a line like this
* in the driver's method list:
*
* @code
* KOBJMETHOD(device_quiesce, foo_quiesce)
* @endcode
*
* @param dev the device being quiesced
*
* @retval 0 success
* @retval non-zero an error occurred while attempting to quiesce the
* device
*
* @see DEVICE_DETACH()
*/
static __inline int DEVICE_QUIESCE(device_t dev)
{
kobjop_t _m;
int rc;
KOBJOPLOOKUP(((kobj_t)dev)->ops,device_quiesce);
rc = ((device_quiesce_t *) _m)(dev);
return (rc);
}
/** @brief Unique descriptor for the DEVICE_REGISTER() method */
extern struct kobjop_desc device_register_desc;
/** @brief A function implementing the DEVICE_REGISTER() method */
typedef void * device_register_t(device_t dev);
/**
* @brief This is called when the driver is asked to register handlers.
*
*
* To include this method in a device driver, use a line like this
* in the driver's method list:
*
* @code
* KOBJMETHOD(device_register, foo_register)
* @endcode
*
* @param dev the device for which handlers are being registered
*
* @retval NULL method not implemented
* @retval non-NULL a pointer to implementation specific static driver state
*
*/
static __inline void * DEVICE_REGISTER(device_t dev)
{
kobjop_t _m;
void * rc;
KOBJOPLOOKUP(((kobj_t)dev)->ops,device_register);
rc = ((device_register_t *) _m)(dev);
return (rc);
}
#endif /* _device_if_h_ */