blob: 517b260159c9ce8a298465fc4ff071e02be4bedf [file] [log] [blame]
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +08001/*
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>
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -070015#include <linux/slab.h>
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -070016#include <linux/kthread.h>
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080017#include <linux/device.h>
18
19#include "greybus.h"
20
21/* Allow greybus to be disabled at boot if needed */
22static bool nogreybus;
23#ifdef MODULE
24module_param(nogreybus, bool, 0444);
25#else
26core_param(nogreybus, bool, 0444);
27#endif
28int greybus_disabled(void)
29{
30 return nogreybus;
31}
32EXPORT_SYMBOL_GPL(greybus_disabled);
33
34static int greybus_match_one_id(struct greybus_device *gdev,
Greg Kroah-Hartman6584c8a2014-09-01 13:31:31 -070035 const struct greybus_module_id *id)
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080036{
Greg Kroah-Hartman6dca7b92014-09-01 13:42:43 -070037 struct greybus_descriptor_module_id *module_id;
38 struct greybus_descriptor_serial_number *serial_num;
39
40 module_id = &gdev->module_id;
41 serial_num = &gdev->serial_number;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080042
43 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
Greg Kroah-Hartman6dca7b92014-09-01 13:42:43 -070044 (id->vendor != le16_to_cpu(module_id->vendor)))
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080045 return 0;
46
47 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
Greg Kroah-Hartman6dca7b92014-09-01 13:42:43 -070048 (id->product != le16_to_cpu(module_id->product)))
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080049 return 0;
50
51 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
Greg Kroah-Hartman6dca7b92014-09-01 13:42:43 -070052 (id->serial_number != le64_to_cpu(serial_num->serial_number)))
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080053 return 0;
54
55 return 1;
56}
57
Greg Kroah-Hartman6584c8a2014-09-01 13:31:31 -070058static const struct greybus_module_id *greybus_match_id(
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080059 struct greybus_device *gdev,
Greg Kroah-Hartman6584c8a2014-09-01 13:31:31 -070060 const struct greybus_module_id *id)
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080061{
62 if (id == NULL)
63 return NULL;
64
Greg Kroah-Hartman6dca7b92014-09-01 13:42:43 -070065 for (; id->vendor || id->product || id->serial_number ||
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080066 id->driver_info ; id++) {
67 if (greybus_match_one_id(gdev, id))
68 return id;
69 }
70
71 return NULL;
72}
73
74static int greybus_device_match(struct device *dev, struct device_driver *drv)
75{
76 struct greybus_driver *driver = to_greybus_driver(dev->driver);
77 struct greybus_device *gdev = to_greybus_device(dev);
Greg Kroah-Hartman6584c8a2014-09-01 13:31:31 -070078 const struct greybus_module_id *id;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080079
80 id = greybus_match_id(gdev, driver->id_table);
81 if (id)
82 return 1;
83 /* FIXME - Dyanmic ids? */
84 return 0;
85}
86
87static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
88{
89 /* struct greybus_device *gdev = to_greybus_device(dev); */
90
91 /* FIXME - add some uevents here... */
92 return 0;
93}
94
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -070095static struct bus_type greybus_bus_type = {
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +080096 .name = "greybus",
97 .match = greybus_device_match,
98 .uevent = greybus_uevent,
99};
100
101static int greybus_probe(struct device *dev)
102{
103 struct greybus_driver *driver = to_greybus_driver(dev->driver);
104 struct greybus_device *gdev = to_greybus_device(dev);
Greg Kroah-Hartman6584c8a2014-09-01 13:31:31 -0700105 const struct greybus_module_id *id;
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800106 int retval;
107
108 /* match id */
109 id = greybus_match_id(gdev, driver->id_table);
110 if (!id)
111 return -ENODEV;
112
113 retval = driver->probe(gdev, id);
114 if (retval)
115 return retval;
116
117 return 0;
118}
119
120static int greybus_remove(struct device *dev)
121{
122 struct greybus_driver *driver = to_greybus_driver(dev->driver);
123 struct greybus_device *gdev = to_greybus_device(dev);
124
125 driver->disconnect(gdev);
126 return 0;
127}
128
129int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
130 const char *mod_name)
131{
132 int retval;
133
134 if (greybus_disabled())
135 return -ENODEV;
136
137 driver->driver.name = driver->name;
138 driver->driver.probe = greybus_probe;
139 driver->driver.remove = greybus_remove;
140 driver->driver.owner = owner;
141 driver->driver.mod_name = mod_name;
142
143 retval = driver_register(&driver->driver);
144 if (retval)
145 return retval;
146
147 pr_info("registered new driver %s\n", driver->name);
148 return 0;
149}
150EXPORT_SYMBOL_GPL(greybus_register_driver);
151
152void greybus_deregister(struct greybus_driver *driver)
153{
154 driver_unregister(&driver->driver);
155}
156EXPORT_SYMBOL_GPL(greybus_deregister);
157
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700158
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700159static void greybus_module_release(struct device *dev)
160{
161 struct greybus_device *gdev = to_greybus_device(dev);
162 int i;
163
164 for (i = 0; i < gdev->num_strings; ++i)
165 kfree(gdev->string[i]);
166 for (i = 0; i < gdev->num_cports; ++i)
167 kfree(gdev->cport[i]);
168 kfree(gdev);
169}
170
171
Greg Kroah-Hartmane24e7252014-09-01 19:01:14 -0700172const u8 *greybus_string(struct greybus_device *gdev, int id)
173{
174 int i;
175 struct gdev_string *string;
176
177 if (!gdev)
178 return NULL;
179
180 for (i = 0; i < gdev->num_strings; ++i) {
181 string = gdev->string[i];
182 if (string->id == id)
183 return &string->string[0];
184 }
185 return NULL;
186}
187
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700188static struct device_type greybus_module_type = {
189 .name = "greybus_module",
190 .release = greybus_module_release,
191};
192
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700193static int gb_init_subdevs(struct greybus_device *gdev,
194 const struct greybus_module_id *id)
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700195{
196 int retval;
197
198 /* Allocate all of the different "sub device types" for this device */
199 retval = gb_i2c_probe(gdev, id);
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700200 if (retval)
201 goto error_i2c;
202
203 retval = gb_gpio_probe(gdev, id);
204 if (retval)
205 goto error_gpio;
206
207 retval = gb_sdio_probe(gdev, id);
208 if (retval)
209 goto error_sdio;
210
211 retval = gb_tty_probe(gdev, id);
212 if (retval)
213 goto error_tty;
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700214 return 0;
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700215
216error_tty:
217 gb_sdio_disconnect(gdev);
218
219error_sdio:
220 gb_gpio_disconnect(gdev);
221
222error_gpio:
223 gb_i2c_disconnect(gdev);
224
225error_i2c:
226 return retval;
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700227}
228
Greg Kroah-Hartman3be03d42014-09-01 19:10:06 -0700229static const struct greybus_module_id fake_gb_id = {
230 GREYBUS_DEVICE(0x42, 0x42)
231};
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700232
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700233static int create_function(struct greybus_device *gdev,
234 struct greybus_descriptor *desc, int desc_size)
235{
236 int header_size = sizeof(struct greybus_descriptor_function);
237
238 if (desc_size != header_size) {
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700239 dev_err(gdev->dev.parent, "invalid function header size %d\n",
240 desc_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700241 return -EINVAL;
242 }
243 memcpy(&gdev->function, &desc->function, header_size);
244 return 0;
245}
246
247static int create_module_id(struct greybus_device *gdev,
248 struct greybus_descriptor *desc, int desc_size)
249{
250 int header_size = sizeof(struct greybus_descriptor_module_id);
251
252 if (desc_size != header_size) {
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700253 dev_err(gdev->dev.parent, "invalid module header size %d\n",
254 desc_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700255 return -EINVAL;
256 }
257 memcpy(&gdev->module_id, &desc->module_id, header_size);
258 return 0;
259}
260
261static int create_serial_number(struct greybus_device *gdev,
262 struct greybus_descriptor *desc, int desc_size)
263{
264 int header_size = sizeof(struct greybus_descriptor_serial_number);
265
266 if (desc_size != header_size) {
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700267 dev_err(gdev->dev.parent, "invalid serial number header size %d\n",
268 desc_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700269 return -EINVAL;
270 }
271 memcpy(&gdev->serial_number, &desc->serial_number, header_size);
272 return 0;
273}
274
275static int create_string(struct greybus_device *gdev,
276 struct greybus_descriptor *desc, int desc_size)
277{
278 int string_size;
279 struct gdev_string *string;
280 int header_size = sizeof(struct greybus_descriptor_string);
281
282 if ((gdev->num_strings + 1) >= MAX_STRINGS_PER_MODULE) {
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700283 dev_err(gdev->dev.parent,
284 "too many strings for this module!\n");
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700285 return -EINVAL;
286 }
287
288 if (desc_size < header_size) {
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700289 dev_err(gdev->dev.parent, "invalid string header size %d\n",
290 desc_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700291 return -EINVAL;
292 }
293
294 string_size = le16_to_cpu(desc->string.length);
295 string = kzalloc(sizeof(*string) + string_size + 1, GFP_KERNEL);
296 if (!string)
297 return -ENOMEM;
298
299 string->length = string_size;
300 string->id = desc->string.id;
301 memcpy(&string->string, &desc->string.string, string_size);
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700302
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700303 gdev->string[gdev->num_strings] = string;
304 gdev->num_strings++;
305
306 return 0;
307}
308
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700309static int create_cport(struct greybus_device *gdev,
310 struct greybus_descriptor *desc, int desc_size)
311{
312 struct gdev_cport *cport;
313 int header_size = sizeof(struct greybus_descriptor_cport);
314
315 if ((gdev->num_cports + 1) >= MAX_CPORTS_PER_MODULE) {
316 dev_err(gdev->dev.parent, "too many cports for this module!\n");
317 return -EINVAL;
318 }
319
320 if (desc_size != header_size) {
321 dev_err(gdev->dev.parent,
322 "invalid serial number header size %d\n", desc_size);
323 return -EINVAL;
324 }
325
326 cport = kzalloc(sizeof(*cport), GFP_KERNEL);
327 if (!cport)
328 return -ENOMEM;
329
330 cport->number = le16_to_cpu(desc->cport.number);
331 cport->size = le16_to_cpu(desc->cport.size);
332 cport->speed = desc->cport.speed;
333
334 gdev->cport[gdev->num_cports] = cport;
335 gdev->num_cports++;
336
337 return 0;
338}
339
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700340/**
341 * greybus_new_device:
342 *
343 * Pass in a buffer that _should_ be a set of greybus descriptor fields and spit
344 * out a greybus device structure.
345 */
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700346struct greybus_device *greybus_new_device(struct device *parent,
347 int module_number, u8 *data, int size)
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700348{
349 struct greybus_device *gdev;
350 struct greybus_descriptor_block_header *block;
351 struct greybus_descriptor *desc;
352 int retval;
353 int overall_size;
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700354 int desc_size;
355 u8 version_major;
356 u8 version_minor;
357
358 /* we have to have at _least_ the block header */
359 if (size <= sizeof(struct greybus_descriptor_block_header))
360 return NULL;
361
362 gdev = kzalloc(sizeof(*gdev), GFP_KERNEL);
363 if (!gdev)
364 return NULL;
365
366 gdev->module_number = module_number;
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700367 gdev->dev.parent = parent;
368 gdev->dev.driver = NULL;
369 gdev->dev.bus = &greybus_bus_type;
370 gdev->dev.type = &greybus_module_type;
371 gdev->dev.groups = greybus_module_groups;
372 gdev->dev.dma_mask = parent->dma_mask;
373 device_initialize(&gdev->dev);
374 dev_set_name(&gdev->dev, "%d", module_number);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700375
376 block = (struct greybus_descriptor_block_header *)data;
377 overall_size = le16_to_cpu(block->size);
378 if (overall_size != size) {
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700379 dev_err(parent, "size != block header size, %d != %d\n", size,
380 overall_size);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700381 goto error;
382 }
383
384 version_major = block->version_major;
385 version_minor = block->version_minor;
386
387 // FIXME - check version major/minor here!
388
389 size -= sizeof(struct greybus_descriptor_block_header);
390 data += sizeof(struct greybus_descriptor_block_header);
391 while (size > 0) {
392 desc = (struct greybus_descriptor *)data;
393 desc_size = le16_to_cpu(desc->header.size);
394
395 switch (desc->header.type) {
396 case GREYBUS_TYPE_FUNCTION:
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700397 retval = create_function(gdev, desc, desc_size);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700398 break;
399
400 case GREYBUS_TYPE_MODULE_ID:
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700401 retval = create_module_id(gdev, desc, desc_size);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700402 break;
403
404 case GREYBUS_TYPE_SERIAL_NUMBER:
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700405 retval = create_serial_number(gdev, desc, desc_size);
406 break;
407
408 case GREYBUS_TYPE_STRING:
409 retval = create_string(gdev, desc, desc_size);
410 break;
411
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700412 case GREYBUS_TYPE_CPORT:
413 retval = create_cport(gdev, desc, desc_size);
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700414 break;
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700415
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700416 case GREYBUS_TYPE_INVALID:
417 default:
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700418 dev_err(parent, "invalid descriptor type %d\n",
419 desc->header.type);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700420 goto error;
421 }
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700422 if (retval)
423 goto error;
424 size -= desc_size;
425 data += desc_size;
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700426 }
Greg Kroah-Hartman526c5c82014-09-01 16:03:31 -0700427
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700428 retval = gb_init_subdevs(gdev, &fake_gb_id);
429 if (retval)
430 goto error;
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700431
432 // FIXME device_add(&gdev->dev);
433
434
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700435 return gdev;
436error:
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700437 greybus_module_release(&gdev->dev);
Greg Kroah-Hartmana239f672014-09-01 14:39:49 -0700438 return NULL;
439}
440
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700441void greybus_remove_device(struct greybus_device *gdev)
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700442{
443 /* tear down all of the "sub device types" for this device */
444 gb_i2c_disconnect(gdev);
445 gb_gpio_disconnect(gdev);
446 gb_sdio_disconnect(gdev);
447 gb_tty_disconnect(gdev);
Greg Kroah-Hartmanb94295e2014-09-01 18:34:28 -0700448
449 // FIXME - device_remove(&gdev->dev);
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700450}
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700451
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700452struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver,
453 struct device *parent)
454{
455 struct greybus_host_device *hd;
456
457 hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
458 if (!hd)
459 return NULL;
460
461 kref_init(&hd->kref);
462
463 return hd;
464}
465EXPORT_SYMBOL_GPL(greybus_create_hd);
466
467
Greg Kroah-Hartman503c1cd2014-08-30 16:21:03 -0700468static int __init gb_init(void)
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700469{
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700470 int retval;
471
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700472 retval = gb_debugfs_init();
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700473 if (retval)
474 return retval;
475
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700476 retval = bus_register(&greybus_bus_type);
477 if (retval)
478 goto error_bus;
479
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700480 retval = gb_thread_init();
481 if (retval)
482 goto error_thread;
483
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700484 // FIXME - more gb core init goes here
485
486 retval = gb_tty_init();
487 if (retval)
488 goto error_tty;
489
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700490 return 0;
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700491
492error_tty:
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700493 gb_thread_destroy();
494
495error_thread:
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700496 bus_unregister(&greybus_bus_type);
497
498error_bus:
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700499 gb_debugfs_cleanup();
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700500
501 return retval;
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700502}
503
Greg Kroah-Hartman503c1cd2014-08-30 16:21:03 -0700504static void __exit gb_exit(void)
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700505{
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700506 gb_tty_exit();
Greg Kroah-Hartman27fb8312014-08-31 13:54:59 -0700507 bus_unregister(&greybus_bus_type);
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700508 gb_debugfs_cleanup();
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700509}
510
511module_init(gb_init);
512module_exit(gb_exit);
513
Greg Kroah-Hartmanc8a797a2014-08-11 15:30:45 +0800514MODULE_LICENSE("GPL");
515MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");