]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/staging/greybus/core.c
greybus: add test_sink driver
[mirror_ubuntu-artful-kernel.git] / drivers / staging / greybus / core.c
CommitLineData
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>
a239f67c 15#include <linux/slab.h>
c8a797a9
GKH
16#include <linux/device.h>
17
18#include "greybus.h"
19
20/* Allow greybus to be disabled at boot if needed */
21static bool nogreybus;
22#ifdef MODULE
23module_param(nogreybus, bool, 0444);
24#else
25core_param(nogreybus, bool, 0444);
26#endif
27int greybus_disabled(void)
28{
29 return nogreybus;
30}
31EXPORT_SYMBOL_GPL(greybus_disabled);
32
33static int greybus_match_one_id(struct greybus_device *gdev,
6584c8af 34 const struct greybus_module_id *id)
c8a797a9 35{
6dca7b97
GKH
36 struct greybus_descriptor_module_id *module_id;
37 struct greybus_descriptor_serial_number *serial_num;
38
39 module_id = &gdev->module_id;
40 serial_num = &gdev->serial_number;
c8a797a9
GKH
41
42 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
6dca7b97 43 (id->vendor != le16_to_cpu(module_id->vendor)))
c8a797a9
GKH
44 return 0;
45
46 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
6dca7b97 47 (id->product != le16_to_cpu(module_id->product)))
c8a797a9
GKH
48 return 0;
49
50 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
6dca7b97 51 (id->serial_number != le64_to_cpu(serial_num->serial_number)))
c8a797a9
GKH
52 return 0;
53
54 return 1;
55}
56
6584c8af 57static const struct greybus_module_id *greybus_match_id(
c8a797a9 58 struct greybus_device *gdev,
6584c8af 59 const struct greybus_module_id *id)
c8a797a9
GKH
60{
61 if (id == NULL)
62 return NULL;
63
6dca7b97 64 for (; id->vendor || id->product || id->serial_number ||
c8a797a9
GKH
65 id->driver_info ; id++) {
66 if (greybus_match_one_id(gdev, id))
67 return id;
68 }
69
70 return NULL;
71}
72
73static int greybus_device_match(struct device *dev, struct device_driver *drv)
74{
75 struct greybus_driver *driver = to_greybus_driver(dev->driver);
76 struct greybus_device *gdev = to_greybus_device(dev);
6584c8af 77 const struct greybus_module_id *id;
c8a797a9
GKH
78
79 id = greybus_match_id(gdev, driver->id_table);
80 if (id)
81 return 1;
82 /* FIXME - Dyanmic ids? */
83 return 0;
84}
85
86static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
87{
88 /* struct greybus_device *gdev = to_greybus_device(dev); */
89
90 /* FIXME - add some uevents here... */
91 return 0;
92}
93
27fb8310 94static struct bus_type greybus_bus_type = {
c8a797a9
GKH
95 .name = "greybus",
96 .match = greybus_device_match,
97 .uevent = greybus_uevent,
98};
99
100static int greybus_probe(struct device *dev)
101{
102 struct greybus_driver *driver = to_greybus_driver(dev->driver);
103 struct greybus_device *gdev = to_greybus_device(dev);
6584c8af 104 const struct greybus_module_id *id;
c8a797a9
GKH
105 int retval;
106
107 /* match id */
108 id = greybus_match_id(gdev, driver->id_table);
109 if (!id)
110 return -ENODEV;
111
112 retval = driver->probe(gdev, id);
113 if (retval)
114 return retval;
115
116 return 0;
117}
118
119static int greybus_remove(struct device *dev)
120{
121 struct greybus_driver *driver = to_greybus_driver(dev->driver);
122 struct greybus_device *gdev = to_greybus_device(dev);
123
124 driver->disconnect(gdev);
125 return 0;
126}
127
128int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
129 const char *mod_name)
130{
131 int retval;
132
133 if (greybus_disabled())
134 return -ENODEV;
135
136 driver->driver.name = driver->name;
137 driver->driver.probe = greybus_probe;
138 driver->driver.remove = greybus_remove;
139 driver->driver.owner = owner;
140 driver->driver.mod_name = mod_name;
141
142 retval = driver_register(&driver->driver);
143 if (retval)
144 return retval;
145
146 pr_info("registered new driver %s\n", driver->name);
147 return 0;
148}
149EXPORT_SYMBOL_GPL(greybus_register_driver);
150
151void greybus_deregister(struct greybus_driver *driver)
152{
153 driver_unregister(&driver->driver);
154}
155EXPORT_SYMBOL_GPL(greybus_deregister);
156
199d68d4 157
b94295e0
GKH
158static void greybus_module_release(struct device *dev)
159{
160 struct greybus_device *gdev = to_greybus_device(dev);
161 int i;
162
163 for (i = 0; i < gdev->num_strings; ++i)
164 kfree(gdev->string[i]);
165 for (i = 0; i < gdev->num_cports; ++i)
166 kfree(gdev->cport[i]);
167 kfree(gdev);
168}
169
170
e24e7257
GKH
171const u8 *greybus_string(struct greybus_device *gdev, int id)
172{
173 int i;
174 struct gdev_string *string;
175
176 if (!gdev)
177 return NULL;
178
179 for (i = 0; i < gdev->num_strings; ++i) {
180 string = gdev->string[i];
181 if (string->id == id)
182 return &string->string[0];
183 }
184 return NULL;
185}
186
b94295e0
GKH
187static struct device_type greybus_module_type = {
188 .name = "greybus_module",
189 .release = greybus_module_release,
190};
191
a239f67c
GKH
192static int gb_init_subdevs(struct greybus_device *gdev,
193 const struct greybus_module_id *id)
199d68d4
GKH
194{
195 int retval;
196
197 /* Allocate all of the different "sub device types" for this device */
198 retval = gb_i2c_probe(gdev, id);
db6e1fd2
GKH
199 if (retval)
200 goto error_i2c;
201
202 retval = gb_gpio_probe(gdev, id);
203 if (retval)
204 goto error_gpio;
205
206 retval = gb_sdio_probe(gdev, id);
207 if (retval)
208 goto error_sdio;
209
210 retval = gb_tty_probe(gdev, id);
211 if (retval)
212 goto error_tty;
33ea3a3f
GKH
213
214 retval = gb_battery_probe(gdev, id);
215 if (retval)
216 goto error_battery;
199d68d4 217 return 0;
db6e1fd2 218
33ea3a3f
GKH
219error_battery:
220 gb_tty_disconnect(gdev);
221
db6e1fd2
GKH
222error_tty:
223 gb_sdio_disconnect(gdev);
224
225error_sdio:
226 gb_gpio_disconnect(gdev);
227
228error_gpio:
229 gb_i2c_disconnect(gdev);
230
231error_i2c:
232 return retval;
199d68d4
GKH
233}
234
3be03d42
GKH
235static const struct greybus_module_id fake_gb_id = {
236 GREYBUS_DEVICE(0x42, 0x42)
237};
a239f67c 238
526c5c8d 239static int create_function(struct greybus_device *gdev,
3d545326
GKH
240 struct greybus_descriptor_function *function,
241 size_t desc_size)
526c5c8d 242{
3d545326
GKH
243 if (desc_size != sizeof(*function)) {
244 dev_err(gdev->dev.parent, "invalid function header size %zu\n",
b94295e0 245 desc_size);
526c5c8d
GKH
246 return -EINVAL;
247 }
3d545326 248 memcpy(&gdev->function, function, desc_size);
526c5c8d
GKH
249 return 0;
250}
251
252static int create_module_id(struct greybus_device *gdev,
3d545326
GKH
253 struct greybus_descriptor_module_id *module_id,
254 size_t desc_size)
526c5c8d 255{
3d545326
GKH
256 if (desc_size != sizeof(*module_id)) {
257 dev_err(gdev->dev.parent, "invalid module header size %zu\n",
b94295e0 258 desc_size);
526c5c8d
GKH
259 return -EINVAL;
260 }
3d545326 261 memcpy(&gdev->module_id, module_id, desc_size);
526c5c8d
GKH
262 return 0;
263}
264
265static int create_serial_number(struct greybus_device *gdev,
3d545326
GKH
266 struct greybus_descriptor_serial_number *serial_num,
267 size_t desc_size)
526c5c8d 268{
3d545326
GKH
269 if (desc_size != sizeof(*serial_num)) {
270 dev_err(gdev->dev.parent, "invalid serial number header size %zu\n",
b94295e0 271 desc_size);
526c5c8d
GKH
272 return -EINVAL;
273 }
3d545326 274 memcpy(&gdev->serial_number, serial_num, desc_size);
526c5c8d
GKH
275 return 0;
276}
277
278static int create_string(struct greybus_device *gdev,
3d545326
GKH
279 struct greybus_descriptor_string *string,
280 size_t desc_size)
526c5c8d
GKH
281{
282 int string_size;
3d545326 283 struct gdev_string *gdev_string;
526c5c8d
GKH
284
285 if ((gdev->num_strings + 1) >= MAX_STRINGS_PER_MODULE) {
b94295e0
GKH
286 dev_err(gdev->dev.parent,
287 "too many strings for this module!\n");
526c5c8d
GKH
288 return -EINVAL;
289 }
290
3d545326
GKH
291 if (desc_size < sizeof(*string)) {
292 dev_err(gdev->dev.parent, "invalid string header size %zu\n",
b94295e0 293 desc_size);
526c5c8d
GKH
294 return -EINVAL;
295 }
296
3d545326
GKH
297 string_size = le16_to_cpu(string->length);
298 gdev_string = kzalloc(sizeof(*gdev_string) + string_size + 1, GFP_KERNEL);
299 if (!gdev_string)
526c5c8d
GKH
300 return -ENOMEM;
301
3d545326
GKH
302 gdev_string->length = string_size;
303 gdev_string->id = string->id;
304 memcpy(&gdev_string->string, &string->string, string_size);
b94295e0 305
3d545326 306 gdev->string[gdev->num_strings] = gdev_string;
526c5c8d
GKH
307 gdev->num_strings++;
308
309 return 0;
310}
311
b94295e0 312static int create_cport(struct greybus_device *gdev,
3d545326
GKH
313 struct greybus_descriptor_cport *cport,
314 size_t desc_size)
b94295e0 315{
3d545326 316 struct gdev_cport *gdev_cport;
b94295e0
GKH
317
318 if ((gdev->num_cports + 1) >= MAX_CPORTS_PER_MODULE) {
319 dev_err(gdev->dev.parent, "too many cports for this module!\n");
320 return -EINVAL;
321 }
322
3d545326 323 if (desc_size != sizeof(*cport)) {
b94295e0 324 dev_err(gdev->dev.parent,
3d545326 325 "invalid serial number header size %zu\n", desc_size);
b94295e0
GKH
326 return -EINVAL;
327 }
328
3d545326
GKH
329 gdev_cport = kzalloc(sizeof(*gdev_cport), GFP_KERNEL);
330 if (!gdev_cport)
b94295e0
GKH
331 return -ENOMEM;
332
3d545326
GKH
333 gdev_cport->number = le16_to_cpu(cport->number);
334 gdev_cport->size = le16_to_cpu(cport->size);
335 gdev_cport->speed = cport->speed;
b94295e0 336
3d545326 337 gdev->cport[gdev->num_cports] = gdev_cport;
b94295e0
GKH
338 gdev->num_cports++;
339
340 return 0;
341}
342
a239f67c 343/**
05ad189c 344 * greybus_new_module:
a239f67c 345 *
05ad189c
AE
346 * Pass in a buffer that _should_ contain a Greybus module manifest
347 * and spit out a greybus device structure.
a239f67c 348 */
05ad189c 349struct greybus_device *greybus_new_module(struct device *parent,
b94295e0 350 int module_number, u8 *data, int size)
a239f67c
GKH
351{
352 struct greybus_device *gdev;
badad68e 353 struct greybus_manifest *manifest;
a239f67c
GKH
354 int retval;
355 int overall_size;
a239f67c
GKH
356 u8 version_major;
357 u8 version_minor;
358
05ad189c 359 /* we have to have at _least_ the manifest header */
badad68e 360 if (size <= sizeof(manifest->header))
a239f67c
GKH
361 return NULL;
362
363 gdev = kzalloc(sizeof(*gdev), GFP_KERNEL);
364 if (!gdev)
365 return NULL;
366
367 gdev->module_number = module_number;
b94295e0
GKH
368 gdev->dev.parent = parent;
369 gdev->dev.driver = NULL;
370 gdev->dev.bus = &greybus_bus_type;
371 gdev->dev.type = &greybus_module_type;
372 gdev->dev.groups = greybus_module_groups;
373 gdev->dev.dma_mask = parent->dma_mask;
374 device_initialize(&gdev->dev);
375 dev_set_name(&gdev->dev, "%d", module_number);
a239f67c 376
badad68e
AE
377 manifest = (struct greybus_manifest *)data;
378 overall_size = le16_to_cpu(manifest->header.size);
a239f67c 379 if (overall_size != size) {
05ad189c
AE
380 dev_err(parent, "size != manifest header size, %d != %d\n",
381 size, overall_size);
a239f67c
GKH
382 goto error;
383 }
384
badad68e
AE
385 version_major = manifest->header.version_major;
386 version_minor = manifest->header.version_minor;
a239f67c 387
a1dc62b0
GKH
388 /* Validate major/minor number */
389 if ((version_major != GREYBUS_VERSION_MAJOR) ||
390 (version_minor != GREYBUS_VERSION_MINOR)) {
391 dev_err(parent,
392 "Invalid greybus versions, expected %d.%d, got %d.%d\n",
393 GREYBUS_VERSION_MAJOR, GREYBUS_VERSION_MINOR,
394 version_major, version_minor);
395 goto error;
396 }
a239f67c 397
badad68e
AE
398 size -= sizeof(manifest->header);
399 data += sizeof(manifest->header);
a239f67c 400 while (size > 0) {
e82bef42
AE
401 struct greybus_descriptor *desc;
402 u16 desc_size;
403 size_t data_size;
404
57fc0a11
AE
405 if (size < sizeof(desc->header)) {
406 dev_err(parent, "remaining size %d too small\n", size);
407 goto error;
408 }
a239f67c
GKH
409 desc = (struct greybus_descriptor *)data;
410 desc_size = le16_to_cpu(desc->header.size);
57fc0a11
AE
411 if (size < desc_size) {
412 dev_err(parent, "descriptor size %d too big\n",
413 desc_size);
414 goto error;
415 }
e82bef42 416 data_size = (size_t)desc_size - sizeof(desc->header);
a239f67c 417
a22e15a1 418 switch (le16_to_cpu(desc->header.type)) {
a239f67c 419 case GREYBUS_TYPE_FUNCTION:
3d545326
GKH
420 retval = create_function(gdev, &desc->function,
421 data_size);
a239f67c
GKH
422 break;
423
424 case GREYBUS_TYPE_MODULE_ID:
3d545326
GKH
425 retval = create_module_id(gdev, &desc->module_id,
426 data_size);
a239f67c
GKH
427 break;
428
429 case GREYBUS_TYPE_SERIAL_NUMBER:
3d545326
GKH
430 retval = create_serial_number(gdev,
431 &desc->serial_number,
432 data_size);
526c5c8d
GKH
433 break;
434
435 case GREYBUS_TYPE_STRING:
3d545326 436 retval = create_string(gdev, &desc->string, data_size);
526c5c8d
GKH
437 break;
438
b94295e0 439 case GREYBUS_TYPE_CPORT:
3d545326 440 retval = create_cport(gdev, &desc->cport, data_size);
a239f67c 441 break;
b94295e0 442
a239f67c
GKH
443 case GREYBUS_TYPE_INVALID:
444 default:
b94295e0
GKH
445 dev_err(parent, "invalid descriptor type %d\n",
446 desc->header.type);
a239f67c
GKH
447 goto error;
448 }
526c5c8d
GKH
449 if (retval)
450 goto error;
451 size -= desc_size;
452 data += desc_size;
a239f67c 453 }
526c5c8d 454
a239f67c
GKH
455 retval = gb_init_subdevs(gdev, &fake_gb_id);
456 if (retval)
457 goto error;
b94295e0
GKH
458
459 // FIXME device_add(&gdev->dev);
460
461
a239f67c
GKH
462 return gdev;
463error:
a5808add 464 put_device(&gdev->dev);
b94295e0 465 greybus_module_release(&gdev->dev);
a239f67c
GKH
466 return NULL;
467}
468
b94295e0 469void greybus_remove_device(struct greybus_device *gdev)
db6e1fd2
GKH
470{
471 /* tear down all of the "sub device types" for this device */
472 gb_i2c_disconnect(gdev);
473 gb_gpio_disconnect(gdev);
474 gb_sdio_disconnect(gdev);
475 gb_tty_disconnect(gdev);
33ea3a3f 476 gb_battery_disconnect(gdev);
b94295e0
GKH
477
478 // FIXME - device_remove(&gdev->dev);
db6e1fd2 479}
199d68d4 480
68f1fc4d
GKH
481static DEFINE_MUTEX(hd_mutex);
482
483static void free_hd(struct kref *kref)
484{
485 struct greybus_host_device *hd;
486
487 hd = container_of(kref, struct greybus_host_device, kref);
488
489 kfree(hd);
490}
491
a39879fc
GKH
492struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver,
493 struct device *parent)
494{
495 struct greybus_host_device *hd;
496
497 hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
498 if (!hd)
499 return NULL;
500
501 kref_init(&hd->kref);
502
503 return hd;
504}
505EXPORT_SYMBOL_GPL(greybus_create_hd);
506
68f1fc4d
GKH
507void greybus_remove_hd(struct greybus_host_device *hd)
508{
509 kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
510}
511EXPORT_SYMBOL_GPL(greybus_remove_hd);
512
a39879fc 513
503c1cdb 514static int __init gb_init(void)
199d68d4 515{
db6e1fd2
GKH
516 int retval;
517
de536e30 518 retval = gb_debugfs_init();
168db1cd
GKH
519 if (retval) {
520 pr_err("debugfs failed\n");
db6e1fd2 521 return retval;
168db1cd 522 }
db6e1fd2 523
27fb8310 524 retval = bus_register(&greybus_bus_type);
168db1cd
GKH
525 if (retval) {
526 pr_err("bus_register failed\n");
27fb8310 527 goto error_bus;
168db1cd 528 }
27fb8310 529
45f3678b 530 retval = gb_ap_init();
168db1cd 531 if (retval) {
45f3678b
GKH
532 pr_err("gb_ap_init failed\n");
533 goto error_ap;
168db1cd 534 }
de536e30 535
45f3678b
GKH
536 retval = gb_gbuf_init();
537 if (retval) {
538 pr_err("gb_gbuf_init failed\n");
539 goto error_gbuf;
540 }
27fb8310
GKH
541
542 retval = gb_tty_init();
168db1cd
GKH
543 if (retval) {
544 pr_err("gb_tty_init failed\n");
27fb8310 545 goto error_tty;
168db1cd 546 }
27fb8310 547
199d68d4 548 return 0;
27fb8310
GKH
549
550error_tty:
45f3678b
GKH
551 gb_gbuf_exit();
552
553error_gbuf:
554 gb_ap_exit();
de536e30 555
45f3678b 556error_ap:
27fb8310
GKH
557 bus_unregister(&greybus_bus_type);
558
559error_bus:
de536e30 560 gb_debugfs_cleanup();
27fb8310
GKH
561
562 return retval;
199d68d4
GKH
563}
564
503c1cdb 565static void __exit gb_exit(void)
199d68d4 566{
db6e1fd2 567 gb_tty_exit();
45f3678b
GKH
568 gb_gbuf_exit();
569 gb_ap_exit();
27fb8310 570 bus_unregister(&greybus_bus_type);
de536e30 571 gb_debugfs_cleanup();
199d68d4
GKH
572}
573
574module_init(gb_init);
575module_exit(gb_exit);
576
c8a797a9
GKH
577MODULE_LICENSE("GPL");
578MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");