1 /*
2  * Copyright (c) 2012 Corey Tabaka
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #pragma once
9 
10 #include <sys/types.h>
11 #include <lk/list.h> // for containerof
12 #include <lk/compiler.h>
13 
14 __BEGIN_CDECLS
15 
16 struct driver;
17 
18 /*
19  * Contains the data pertaining to an instance of a device. More than one
20  * instance may exist for a given driver type (i.e. uart0, uart1, etc..).
21  */
22 struct device {
23     const char *name;
24     const struct driver *driver;
25 
26     uint32_t flags;
27 
28     /* instance specific config data populated at instantiation */
29     const void *config;
30 
31     /* instance specific data populated by the driver at init */
32     void *state;
33 
34     // TODO: add generic state, such as suspend/resume state, etc...
35     enum {
36         DEVICE_UNINITIALIZED,
37         DEVICE_INITIALIZED,
38         DEVICE_INITIALIZED_FAILED,
39     } device_state;
40 };
41 
42 /* set this flag to auto initialize the device when device_init_all is called */
43 #define DEVICE_FLAG_AUTOINIT 0x1
44 
45 /* device class, mainly used as a unique magic pointer to validate ops */
46 struct device_class {
47     const char *name;
48 };
49 
50 /* standard driver ops; extensions should contain this ops structure */
51 struct driver_ops {
52     const struct device_class *device_class;
53 
54     status_t (*init)(struct device *dev);
55     status_t (*fini)(struct device *dev);
56 
57     status_t (*suspend)(struct device *dev);
58     status_t (*resume)(struct device *dev);
59 };
60 
61 /* describes a driver, one per driver type */
62 struct driver {
63     const char *type;
64     const struct driver_ops *ops;
65 };
66 
67 /* macro-expanding concat */
68 #define concat(a, b) __ex_concat(a, b)
69 #define __ex_concat(a, b) a ## b
70 
71 #define DRIVER_EXPORT(type_, ops_) \
72     const struct driver concat(__driver_, type_) \
73         __ALIGNED(sizeof(void *)) __SECTION("drivers") = { \
74         .type = #type_, \
75         .ops = ops_, \
76     }
77 
78 #define DEVICE_INSTANCE(type_, name_, config_, flags_) \
79     extern const struct driver concat(__driver_, type_); \
80     struct device concat(__device_, concat(type_, concat(_, name_))) \
81         __ALIGNED(sizeof(void *)) __SECTION("devices") = { \
82         .name = #name_, \
83         .driver = &concat(__driver_, type_), \
84         .flags = flags_, \
85         .config = config_, \
86         .state = NULL, \
87         .device_state = DEVICE_UNINITIALIZED, \
88     }
89 
90 /*
91  * returns the driver specific ops pointer given the device instance, specific
92  * ops type, and generic ops member name within the specific ops structure.
93  */
94 #define device_get_driver_ops(dev, type, member) ({ \
95     type *__ops = NULL; \
96     if (dev && dev->driver && dev->driver->ops) \
97         __ops = containerof(dev->driver->ops, type, member); \
98     __ops; \
99 })
100 
101 #define device_get_by_name(type_, name_) ({ \
102     extern struct device concat(__device_, concat(type_, concat(_, name_))); \
103     &concat(__device_, concat(type_, concat(_, name_))); \
104 })
105 
106 /* initialize all static devices with AUTOINIT flag set */
107 status_t device_init_all(void);
108 
109 status_t device_fini_all(void);
110 
111 status_t device_init(struct device *dev);
112 status_t device_fini(struct device *dev);
113 
114 status_t device_suspend(struct device *dev);
115 status_t device_resume(struct device *dev);
116 
117 __END_CDECLS
118 
119