greybus: October 1 updates
[cascardo/linux.git] / drivers / staging / greybus / module.c
1 /*
2  * Greybus modules
3  *
4  * Copyright 2014 Google Inc.
5  *
6  * Released under the GPLv2 only.
7  */
8
9 #include "greybus.h"
10
11 /* XXX This could be per-host device */
12 static DEFINE_SPINLOCK(gb_modules_lock);
13
14 static int gb_module_match_one_id(struct gb_module *gmod,
15                                 const struct greybus_module_id *id)
16 {
17         if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
18             (id->vendor != gmod->vendor))
19                 return 0;
20
21         if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
22             (id->product != gmod->product))
23                 return 0;
24
25         if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
26             (id->unique_id != gmod->unique_id))
27                 return 0;
28
29         return 1;
30 }
31
32 const struct greybus_module_id *gb_module_match_id(struct gb_module *gmod,
33                                 const struct greybus_module_id *id)
34 {
35         if (id == NULL)
36                 return NULL;
37
38         for (; id->vendor || id->product || id->unique_id ||
39                         id->driver_info; id++) {
40                 if (gb_module_match_one_id(gmod, id))
41                         return id;
42         }
43
44         return NULL;
45 }
46
47 /*
48  * A Greybus module represents a user-replacable component on an Ara
49  * phone.
50  *
51  * Create a gb_module structure to represent a discovered module.
52  * The position within the Endo is encoded in the "module_id" argument.
53  * Returns a pointer to the new module or a null pointer if a
54  * failure occurs due to memory exhaustion.
55  */
56 struct gb_module *gb_module_create(struct greybus_host_device *hd, u8 module_id)
57 {
58         struct gb_module *module;
59
60         module = kzalloc(sizeof(*module), GFP_KERNEL);
61         if (!module)
62                 return NULL;
63
64         module->hd = hd;                /* XXX refcount? */
65         module->module_id = module_id;
66         INIT_LIST_HEAD(&module->interfaces);
67
68         spin_lock_irq(&gb_modules_lock);
69         list_add_tail(&module->links, &hd->modules);
70         spin_unlock_irq(&gb_modules_lock);
71
72         return module;
73 }
74
75 /*
76  * Tear down a previously set up module.
77  */
78 void gb_module_destroy(struct gb_module *module)
79 {
80         if (WARN_ON(!module))
81                 return;
82
83         kfree(module->product_string);
84         kfree(module->vendor_string);
85
86         spin_lock_irq(&gb_modules_lock);
87         list_del(&module->links);
88         spin_unlock_irq(&gb_modules_lock);
89
90         /* kref_put(module->hd); */
91
92         kfree(module);
93 }