]>
Commit | Line | Data |
---|---|---|
c8a797a9 GKH |
1 | /* |
2 | * Greybus "Core" | |
3 | * | |
4 | * Copyright 2014 Google Inc. | |
5 | * | |
6 | * Released under the GPLv2 only. | |
7 | */ | |
8 | ||
9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
10 | ||
11 | #include <linux/types.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/moduleparam.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/device.h> | |
16 | ||
17 | #include "greybus.h" | |
18 | ||
19 | /* Allow greybus to be disabled at boot if needed */ | |
20 | static bool nogreybus; | |
21 | #ifdef MODULE | |
22 | module_param(nogreybus, bool, 0444); | |
23 | #else | |
24 | core_param(nogreybus, bool, 0444); | |
25 | #endif | |
26 | int greybus_disabled(void) | |
27 | { | |
28 | return nogreybus; | |
29 | } | |
30 | EXPORT_SYMBOL_GPL(greybus_disabled); | |
31 | ||
32 | static int greybus_match_one_id(struct greybus_device *gdev, | |
33 | const struct greybus_device_id *id) | |
34 | { | |
35 | struct greybus_descriptor *des = &gdev->descriptor; | |
36 | ||
37 | if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) && | |
38 | (des->wVendor != id->wVendor)) | |
39 | return 0; | |
40 | ||
41 | if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) && | |
42 | (des->wProduct != id->wProduct)) | |
43 | return 0; | |
44 | ||
45 | if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) && | |
46 | (des->lSerialNumber != id->lSerialNumber)) | |
47 | return 0; | |
48 | ||
49 | return 1; | |
50 | } | |
51 | ||
52 | static const struct greybus_device_id *greybus_match_id( | |
53 | struct greybus_device *gdev, | |
54 | const struct greybus_device_id *id) | |
55 | { | |
56 | if (id == NULL) | |
57 | return NULL; | |
58 | ||
59 | for (; id->wVendor || id->wProduct || id->lSerialNumber || | |
60 | id->driver_info ; id++) { | |
61 | if (greybus_match_one_id(gdev, id)) | |
62 | return id; | |
63 | } | |
64 | ||
65 | return NULL; | |
66 | } | |
67 | ||
68 | static int greybus_device_match(struct device *dev, struct device_driver *drv) | |
69 | { | |
70 | struct greybus_driver *driver = to_greybus_driver(dev->driver); | |
71 | struct greybus_device *gdev = to_greybus_device(dev); | |
72 | const struct greybus_device_id *id; | |
73 | ||
74 | id = greybus_match_id(gdev, driver->id_table); | |
75 | if (id) | |
76 | return 1; | |
77 | /* FIXME - Dyanmic ids? */ | |
78 | return 0; | |
79 | } | |
80 | ||
81 | static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env) | |
82 | { | |
83 | /* struct greybus_device *gdev = to_greybus_device(dev); */ | |
84 | ||
85 | /* FIXME - add some uevents here... */ | |
86 | return 0; | |
87 | } | |
88 | ||
89 | struct bus_type greybus_bus_type = { | |
90 | .name = "greybus", | |
91 | .match = greybus_device_match, | |
92 | .uevent = greybus_uevent, | |
93 | }; | |
94 | ||
95 | static int greybus_probe(struct device *dev) | |
96 | { | |
97 | struct greybus_driver *driver = to_greybus_driver(dev->driver); | |
98 | struct greybus_device *gdev = to_greybus_device(dev); | |
99 | const struct greybus_device_id *id; | |
100 | int retval; | |
101 | ||
102 | /* match id */ | |
103 | id = greybus_match_id(gdev, driver->id_table); | |
104 | if (!id) | |
105 | return -ENODEV; | |
106 | ||
107 | retval = driver->probe(gdev, id); | |
108 | if (retval) | |
109 | return retval; | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | static int greybus_remove(struct device *dev) | |
115 | { | |
116 | struct greybus_driver *driver = to_greybus_driver(dev->driver); | |
117 | struct greybus_device *gdev = to_greybus_device(dev); | |
118 | ||
119 | driver->disconnect(gdev); | |
120 | return 0; | |
121 | } | |
122 | ||
123 | int greybus_register_driver(struct greybus_driver *driver, struct module *owner, | |
124 | const char *mod_name) | |
125 | { | |
126 | int retval; | |
127 | ||
128 | if (greybus_disabled()) | |
129 | return -ENODEV; | |
130 | ||
131 | driver->driver.name = driver->name; | |
132 | driver->driver.probe = greybus_probe; | |
133 | driver->driver.remove = greybus_remove; | |
134 | driver->driver.owner = owner; | |
135 | driver->driver.mod_name = mod_name; | |
136 | ||
137 | retval = driver_register(&driver->driver); | |
138 | if (retval) | |
139 | return retval; | |
140 | ||
141 | pr_info("registered new driver %s\n", driver->name); | |
142 | return 0; | |
143 | } | |
144 | EXPORT_SYMBOL_GPL(greybus_register_driver); | |
145 | ||
146 | void greybus_deregister(struct greybus_driver *driver) | |
147 | { | |
148 | driver_unregister(&driver->driver); | |
149 | } | |
150 | EXPORT_SYMBOL_GPL(greybus_deregister); | |
151 | ||
199d68d4 GKH |
152 | |
153 | static int new_device(struct greybus_device *gdev, | |
154 | const struct greybus_device_id *id) | |
155 | { | |
156 | int retval; | |
157 | ||
158 | /* Allocate all of the different "sub device types" for this device */ | |
159 | retval = gb_i2c_probe(gdev, id); | |
db6e1fd2 GKH |
160 | if (retval) |
161 | goto error_i2c; | |
162 | ||
163 | retval = gb_gpio_probe(gdev, id); | |
164 | if (retval) | |
165 | goto error_gpio; | |
166 | ||
167 | retval = gb_sdio_probe(gdev, id); | |
168 | if (retval) | |
169 | goto error_sdio; | |
170 | ||
171 | retval = gb_tty_probe(gdev, id); | |
172 | if (retval) | |
173 | goto error_tty; | |
199d68d4 | 174 | return 0; |
db6e1fd2 GKH |
175 | |
176 | error_tty: | |
177 | gb_sdio_disconnect(gdev); | |
178 | ||
179 | error_sdio: | |
180 | gb_gpio_disconnect(gdev); | |
181 | ||
182 | error_gpio: | |
183 | gb_i2c_disconnect(gdev); | |
184 | ||
185 | error_i2c: | |
186 | return retval; | |
199d68d4 GKH |
187 | } |
188 | ||
db6e1fd2 GKH |
189 | static void remove_device(struct greybus_device *gdev) |
190 | { | |
191 | /* tear down all of the "sub device types" for this device */ | |
192 | gb_i2c_disconnect(gdev); | |
193 | gb_gpio_disconnect(gdev); | |
194 | gb_sdio_disconnect(gdev); | |
195 | gb_tty_disconnect(gdev); | |
196 | } | |
199d68d4 | 197 | |
503c1cdb | 198 | static int __init gb_init(void) |
199d68d4 | 199 | { |
db6e1fd2 GKH |
200 | int retval; |
201 | ||
202 | retval = gb_tty_init(); | |
203 | if (retval) | |
204 | return retval; | |
205 | ||
199d68d4 GKH |
206 | return 0; |
207 | } | |
208 | ||
503c1cdb | 209 | static void __exit gb_exit(void) |
199d68d4 | 210 | { |
db6e1fd2 | 211 | gb_tty_exit(); |
199d68d4 GKH |
212 | } |
213 | ||
214 | module_init(gb_init); | |
215 | module_exit(gb_exit); | |
216 | ||
c8a797a9 GKH |
217 | MODULE_LICENSE("GPL"); |
218 | MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>"); |