greybus: connection: remove legacy protocol id from core
[cascardo/linux.git] / drivers / staging / greybus / legacy.c
1 /*
2  * Greybus legacy-protocol driver
3  *
4  * Copyright 2015 Google Inc.
5  * Copyright 2015 Linaro Ltd.
6  *
7  * Released under the GPLv2 only.
8  */
9
10 #include "greybus.h"
11 #include "legacy.h"
12 #include "protocol.h"
13
14
15 struct legacy_connection {
16         struct gb_connection *connection;
17         bool initialized;
18         u8 protocol_id;
19 };
20
21 struct legacy_data {
22         size_t num_cports;
23         struct legacy_connection *connections;
24 };
25
26
27 static int legacy_connection_get_version(struct gb_connection *connection)
28 {
29         int ret;
30
31         ret = gb_protocol_get_version(connection);
32         if (ret) {
33                 dev_err(&connection->hd->dev,
34                         "%s: failed to get protocol version: %d\n",
35                         connection->name, ret);
36                 return ret;
37         }
38
39         return 0;
40 }
41
42 static int legacy_connection_bind_protocol(struct legacy_connection *lc)
43 {
44         struct gb_connection *connection = lc->connection;
45         struct gb_protocol *protocol;
46         u8 major, minor;
47
48         /*
49          * The legacy protocols have always been looked up using a hard-coded
50          * version of 0.1, despite (or perhaps rather, due to) the fact that
51          * module version negotiation could not take place until after the
52          * protocol was bound.
53          */
54         major = 0;
55         minor = 1;
56
57         protocol = gb_protocol_get(lc->protocol_id, major, minor);
58         if (!protocol) {
59                 dev_err(&connection->hd->dev,
60                                 "protocol 0x%02x version %u.%u not found\n",
61                                 lc->protocol_id, major, minor);
62                 return -EPROTONOSUPPORT;
63         }
64         connection->protocol = protocol;
65
66         return 0;
67 }
68
69 static void legacy_connection_unbind_protocol(struct gb_connection *connection)
70 {
71         struct gb_protocol *protocol = connection->protocol;
72
73         gb_protocol_put(protocol);
74
75         connection->protocol = NULL;
76 }
77
78 static int legacy_request_handler(struct gb_operation *operation)
79 {
80         struct gb_protocol *protocol = operation->connection->protocol;
81
82         return protocol->request_recv(operation->type, operation);
83 }
84
85 static int legacy_connection_init(struct legacy_connection *lc)
86 {
87         struct gb_connection *connection = lc->connection;
88         gb_request_handler_t handler;
89         int ret;
90
91         dev_dbg(&connection->bundle->dev, "%s - %s\n", __func__,
92                         connection->name);
93
94         ret = legacy_connection_bind_protocol(lc);
95         if (ret)
96                 return ret;
97
98         if (connection->protocol->request_recv)
99                 handler = legacy_request_handler;
100         else
101                 handler = NULL;
102
103         ret = gb_connection_enable(connection, handler);
104         if (ret)
105                 goto err_unbind_protocol;
106
107         ret = legacy_connection_get_version(connection);
108         if (ret)
109                 goto err_disable;
110
111         ret = connection->protocol->connection_init(connection);
112         if (ret)
113                 goto err_disable;
114
115         lc->initialized = true;
116
117         return 0;
118
119 err_disable:
120         gb_connection_disable(connection);
121 err_unbind_protocol:
122         legacy_connection_unbind_protocol(connection);
123
124         return ret;
125 }
126
127 static void legacy_connection_exit(struct legacy_connection *lc)
128 {
129         struct gb_connection *connection = lc->connection;
130
131         if (!lc->initialized)
132                 return;
133
134         gb_connection_disable(connection);
135
136         connection->protocol->connection_exit(connection);
137
138         legacy_connection_unbind_protocol(connection);
139
140         lc->initialized = false;
141 }
142
143 static int legacy_connection_create(struct legacy_connection *lc,
144                                         struct gb_bundle *bundle,
145                                         struct greybus_descriptor_cport *desc)
146 {
147         struct gb_connection *connection;
148
149         connection = gb_connection_create(bundle, le16_to_cpu(desc->id));
150         if (IS_ERR(connection))
151                 return PTR_ERR(connection);
152
153         lc->connection = connection;
154         lc->protocol_id = desc->protocol_id;
155
156         return 0;
157 }
158
159 static void legacy_connection_destroy(struct legacy_connection *lc)
160 {
161         gb_connection_destroy(lc->connection);
162 }
163
164 static int legacy_probe(struct gb_bundle *bundle,
165                         const struct greybus_bundle_id *id)
166 {
167         struct greybus_descriptor_cport *cport_desc;
168         struct legacy_data *data;
169         struct legacy_connection *lc;
170         int i;
171         int ret;
172
173         dev_dbg(&bundle->dev,
174                         "%s - bundle class = 0x%02x, num_cports = %zu\n",
175                         __func__, bundle->class, bundle->num_cports);
176
177         data = kzalloc(sizeof(*data), GFP_KERNEL);
178         if (!data)
179                 return -ENOMEM;
180
181         data->num_cports = bundle->num_cports;
182         data->connections = kcalloc(data->num_cports,
183                                                 sizeof(*data->connections),
184                                                 GFP_KERNEL);
185         if (!data->connections) {
186                 ret = -ENOMEM;
187                 goto err_free_data;
188         }
189
190         for (i = 0; i < data->num_cports; ++i) {
191                 cport_desc = &bundle->cport_desc[i];
192                 lc = &data->connections[i];
193
194                 ret = legacy_connection_create(lc, bundle, cport_desc);
195                 if (ret)
196                         goto err_connections_destroy;
197         }
198
199         greybus_set_drvdata(bundle, data);
200
201         for (i = 0; i < data->num_cports; ++i) {
202                 lc = &data->connections[i];
203
204                 ret = legacy_connection_init(lc);
205                 if (ret)
206                         goto err_connections_disable;
207         }
208
209         return 0;
210
211 err_connections_disable:
212         for (--i; i >= 0; --i)
213                 legacy_connection_exit(&data->connections[i]);
214 err_connections_destroy:
215         for (i = 0; i < data->num_cports; ++i)
216                 legacy_connection_destroy(&data->connections[i]);
217         kfree(data->connections);
218 err_free_data:
219         kfree(data);
220
221         return ret;
222 }
223
224 static void legacy_disconnect(struct gb_bundle *bundle)
225 {
226         struct legacy_data *data = greybus_get_drvdata(bundle);
227         int i;
228
229         dev_dbg(&bundle->dev, "%s - bundle class = 0x%02x\n", __func__,
230                         bundle->class);
231
232         for (i = 0; i < data->num_cports; ++i) {
233                 legacy_connection_exit(&data->connections[i]);
234                 legacy_connection_destroy(&data->connections[i]);
235         }
236
237         kfree(data->connections);
238         kfree(data);
239 }
240
241 static const struct greybus_bundle_id legacy_id_table[] = {
242         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_GPIO) },
243         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_I2C) },
244         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_UART) },
245         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_HID) },
246         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_USB) },
247         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SDIO) },
248         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_POWER_SUPPLY) },
249         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_PWM) },
250         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SPI) },
251         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_DISPLAY) },
252         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_CAMERA) },
253         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SENSOR) },
254         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LIGHTS) },
255         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_VIBRATOR) },
256         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LOOPBACK) },
257         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_AUDIO_MGMT) },
258         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_AUDIO_DATA) },
259         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SVC) },
260         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_FIRMWARE) },
261         { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_RAW) },
262         { }
263 };
264 MODULE_DEVICE_TABLE(greybus, legacy_id_table);
265
266 static struct greybus_driver legacy_driver = {
267         .name           = "legacy",
268         .probe          = legacy_probe,
269         .disconnect     = legacy_disconnect,
270         .id_table       = legacy_id_table,
271 };
272
273 int gb_legacy_init(void)
274 {
275         return greybus_register(&legacy_driver);
276 }
277
278 void gb_legacy_exit(void)
279 {
280         greybus_deregister(&legacy_driver);
281 }