blob: 699cd003e3673d4f5aec907d9847be06fc3e7965 [file] [log] [blame]
Alex Eldere1e9dbd2014-10-01 21:54:11 -05001/*
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 */
12static DEFINE_SPINLOCK(gb_modules_lock);
13
14static int gb_module_match_one_id(struct gb_module *gmod,
15 const struct greybus_module_id *id)
16{
Alex Eldere1e9dbd2014-10-01 21:54:11 -050017 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_VENDOR) &&
Alex Elderb09c94a2014-10-01 21:54:16 -050018 (id->vendor != gmod->vendor))
Alex Eldere1e9dbd2014-10-01 21:54:11 -050019 return 0;
20
21 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_PRODUCT) &&
Alex Elderb09c94a2014-10-01 21:54:16 -050022 (id->product != gmod->product))
Alex Eldere1e9dbd2014-10-01 21:54:11 -050023 return 0;
24
25 if ((id->match_flags & GREYBUS_DEVICE_ID_MATCH_SERIAL) &&
Alex Elder63cc9322014-10-02 12:30:02 -050026 (id->unique_id != gmod->unique_id))
Alex Eldere1e9dbd2014-10-01 21:54:11 -050027 return 0;
28
29 return 1;
30}
31
32const 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
Alex Elder63cc9322014-10-02 12:30:02 -050038 for (; id->vendor || id->product || id->unique_id ||
Alex Eldere1e9dbd2014-10-01 21:54:11 -050039 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 */
56struct gb_module *gb_module_create(struct greybus_host_device *hd, u8 module_id)
57{
Alex Elder574341c2014-10-16 06:35:35 -050058 struct gb_module *gmod;
Alex Eldere1e9dbd2014-10-01 21:54:11 -050059
Alex Elder574341c2014-10-16 06:35:35 -050060 gmod = kzalloc(sizeof(*gmod), GFP_KERNEL);
61 if (!gmod)
Alex Eldere1e9dbd2014-10-01 21:54:11 -050062 return NULL;
63
Alex Elder574341c2014-10-16 06:35:35 -050064 gmod->hd = hd; /* XXX refcount? */
65 gmod->module_id = module_id;
66 INIT_LIST_HEAD(&gmod->interfaces);
Alex Eldere1e9dbd2014-10-01 21:54:11 -050067
68 spin_lock_irq(&gb_modules_lock);
Alex Elder574341c2014-10-16 06:35:35 -050069 list_add_tail(&gmod->links, &hd->modules);
Alex Eldere1e9dbd2014-10-01 21:54:11 -050070 spin_unlock_irq(&gb_modules_lock);
71
Alex Elder574341c2014-10-16 06:35:35 -050072 return gmod;
Alex Eldere1e9dbd2014-10-01 21:54:11 -050073}
74
75/*
76 * Tear down a previously set up module.
77 */
Alex Elder574341c2014-10-16 06:35:35 -050078void gb_module_destroy(struct gb_module *gmod)
Alex Eldere1e9dbd2014-10-01 21:54:11 -050079{
Alex Elder574341c2014-10-16 06:35:35 -050080 if (WARN_ON(!gmod))
Alex Eldere1e9dbd2014-10-01 21:54:11 -050081 return;
82
Alex Elder574341c2014-10-16 06:35:35 -050083 kfree(gmod->product_string);
84 kfree(gmod->vendor_string);
Alex Elderb09c94a2014-10-01 21:54:16 -050085
Alex Eldere1e9dbd2014-10-01 21:54:11 -050086 spin_lock_irq(&gb_modules_lock);
Alex Elder574341c2014-10-16 06:35:35 -050087 list_del(&gmod->links);
Alex Eldere1e9dbd2014-10-01 21:54:11 -050088 spin_unlock_irq(&gb_modules_lock);
89
90 /* kref_put(module->hd); */
91
Alex Elder574341c2014-10-16 06:35:35 -050092 kfree(gmod);
93}
94
95void gb_module_interfaces_init(struct gb_module *gmod)
96{
97 struct gb_interface *interface;
98 int ret = 0;
99
100 list_for_each_entry(interface, &gmod->interfaces, links) {
101 ret = gb_interface_connections_init(interface);
102 if (ret)
103 dev_err(gmod->hd->parent,
104 "module interface init error %d\n", ret);
105 }
Alex Eldere1e9dbd2014-10-01 21:54:11 -0500106}