1 /*
2  * Copyright (c) 2012 Corey Tabaka
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #ifndef __DEV_DRIVER_H
24 #define __DEV_DRIVER_H
25 
26 #include <sys/types.h>
27 #include <list.h> // for containerof
28 #include <compiler.h>
29 
30 struct driver;
31 
32 /*
33  * Contains the data pertaining to an instance of a device. More than one
34  * instance may exist for a given driver type (i.e. uart0, uart1, etc..).
35  */
36 struct device {
37     const char *name;
38     const struct driver *driver;
39 
40     /* instance specific config data populated at instantiation */
41     const void *config;
42 
43     /* instance specific data populated by the driver at init */
44     void *state;
45 
46     // TODO: add generic state, such as suspend/resume state, etc...
47 };
48 
49 /* device class, mainly used as a unique magic pointer to validate ops */
50 struct device_class {
51     const char *name;
52 };
53 
54 /* standard driver ops; extensions should contain this ops structure */
55 struct driver_ops {
56     const struct device_class *device_class;
57 
58     status_t (*init)(struct device *dev);
59     status_t (*fini)(struct device *dev);
60 
61     status_t (*suspend)(struct device *dev);
62     status_t (*resume)(struct device *dev);
63 };
64 
65 /* describes a driver, one per driver type */
66 struct driver {
67     const char *type;
68     const struct driver_ops *ops;
69 };
70 
71 /* macro-expanding concat */
72 #define concat(a, b) __ex_concat(a, b)
73 #define __ex_concat(a, b) a ## b
74 
75 #define DRIVER_EXPORT(type_, ops_) \
76     const struct driver concat(__driver_, type_) \
77         __ALIGNED(sizeof(void *)) __SECTION(".drivers") = { \
78         .type = #type_, \
79         .ops = ops_, \
80     }
81 
82 #define DEVICE_INSTANCE(type_, name_, config_) \
83     extern struct driver concat(__driver_, type_); \
84     struct device concat(__device_, concat(type_, concat(_, name_))) \
85         __ALIGNED(sizeof(void *)) __SECTION(".devices") = { \
86         .name = #name_, \
87         .driver = &concat(__driver_, type_), \
88         .config = config_, \
89     }
90 
91 /*
92  * returns the driver specific ops pointer given the device instance, specific
93  * ops type, and generic ops member name within the specific ops structure.
94  */
95 #define device_get_driver_ops(dev, type, member) ({ \
96     type *__ops = NULL; \
97     if (dev && dev->driver && dev->driver->ops) \
98         __ops = containerof(dev->driver->ops, type, member); \
99     __ops; \
100 })
101 
102 #define device_get_by_name(type_, name_) ({ \
103     extern struct device concat(__device_, concat(type_, concat(_, name_))); \
104     &concat(__device_, concat(type_, concat(_, name_))); \
105 })
106 
107 status_t device_init_all(void);
108 status_t device_fini_all(void);
109 
110 status_t device_init(struct device *dev);
111 status_t device_fini(struct device *dev);
112 
113 status_t device_suspend(struct device *dev);
114 status_t device_resume(struct device *dev);
115 
116 #endif
117 
118