0bcb10bd23f5188423368756a554110e0d89ee29
[platform/adaptation/samsung_exynos/device-manager-plugin-odroid.git] / hw / usb_gadget / usb_gadget.c
1 /*
2  * libdevice-node
3  *
4  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #ifndef __HW_USB_GADGET_SIMPLE_TRANSLATOR_H__
20
21 #include <hw/usb_gadget.h>
22
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <string.h>
26
27 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
28 #define zalloc(amount) calloc(1, amount)
29
30 /* Based on slp-gadget and initial version of USB HAL by Taeyoung Kim */
31 #define DEFAULT_VID 0x04e8
32 #define DEFAULT_PID 0x6860
33 #define DEFAULT_BCD_DEVICE 0xffff
34
35 #define DEFAULT_LANG 0x409 /* US_en */
36 #define DEFAULT_MANUFACTURER "Samsung"
37 #define DEFAULT_PRODUCT "TIZEN"
38 #define DEFAULT_SERIAL "01234TEST"
39
40 #define DEFAULT_BMATTRIBUTES ((1 << 7) | (1 << 6))
41 #define DEFAULT_MAX_POWER 500
42
43 static void simple_cleanup_config(struct usb_configuration *config)
44 {
45         int i;
46
47         if (!config)
48                 return;
49
50         if (config->strs) {
51                 for (i = 0; config->strs[i].lang_code; ++i)
52                         free(config->strs[i].config_str);
53
54                 free(config->strs);
55         }
56
57         /*
58          * Each function will be free later,
59          * for now we cleanup only pointers.
60          */
61         if (config->funcs)
62                 free(config->funcs);
63
64         free(config);
65 }
66
67 static void simple_cleanup_gadget(struct usb_gadget *gadget)
68 {
69         int i;
70
71         if (!gadget)
72                 return;
73
74         if (gadget->strs) {
75                 for (i = 0; gadget->strs[i].lang_code; ++i) {
76                         free(gadget->strs[i].manufacturer);
77                         free(gadget->strs[i].product);
78                         free(gadget->strs[i].serial);
79                 }
80                 free(gadget->strs);
81         }
82
83         if (gadget->configs) {
84                 for (i = 0; gadget->configs[i]; ++i)
85                         simple_cleanup_config(gadget->configs[i]);
86
87                 free(gadget->configs);
88         }
89
90         if (gadget->funcs) {
91                 for (i = 0; gadget->funcs[i]; ++i)
92                         gadget->funcs[i]->free_func(gadget->funcs[i]);
93
94                 free(gadget->funcs);
95         }
96
97         free(gadget);
98 }
99
100 static int alloc_default_config(struct usb_configuration **_config)
101 {
102         struct usb_configuration *config;
103
104         config = zalloc(sizeof(*config));
105         if (!config)
106                 goto out;
107
108         config->strs = calloc(1, sizeof(*config->strs));
109         if (!config->strs)
110                 goto free_config;
111
112         config->attrs.bmAttributs = DEFAULT_BMATTRIBUTES;
113         config->attrs.MaxPower = DEFAULT_MAX_POWER;
114
115         *_config = config;
116
117         return 0;
118
119 free_config:
120         free(config);
121 out:
122         return -ENOMEM;
123 }
124
125 static int alloc_default_gadget(struct usb_gadget **_gadget)
126 {
127         struct usb_gadget *gadget;
128         struct usb_gadget_strings *strs;
129         struct usb_configuration **configs;
130
131         gadget = zalloc(sizeof(*gadget));
132         if (!gadget)
133                 goto out;
134
135         gadget->attrs.idVendor = DEFAULT_VID;
136         gadget->attrs.idProduct = DEFAULT_PID;
137         gadget->attrs.bcdDevice = DEFAULT_BCD_DEVICE;
138
139         strs = calloc(2, sizeof(*strs));
140         if (!strs)
141                 goto free_gadget;
142
143         strs[0].lang_code = 0x409;
144         strs[0].manufacturer = strdup(DEFAULT_MANUFACTURER);
145         strs[0].product = strdup(DEFAULT_PRODUCT);
146         strs[0].serial = strdup(DEFAULT_SERIAL);
147
148         if (!strs[0].manufacturer || !strs[0].product || !strs[0].serial)
149                 goto free_strs;
150
151         gadget->strs = strs;
152
153         /* slp-gadget use max 2 confiuration and NULL termination */
154         configs = calloc(3, sizeof(*configs));
155         if (!configs)
156                 goto free_strs;
157
158         gadget->configs = configs;
159         *_gadget = gadget;
160
161         return 0;
162
163 free_strs:
164         free(strs[0].manufacturer);
165         free(strs[0].product);
166         free(strs[0].serial);
167         free(strs);
168 free_gadget:
169         free(gadget);
170 out:
171         return -ENOMEM;
172 }
173
174 static inline struct usb_function *find_func(struct usb_gadget *gadget,
175                                             int func_id)
176 {
177         int i;
178
179         for (i = 0; gadget->funcs[i] && gadget->funcs[i]->id != func_id; ++i);
180
181         return gadget->funcs[i];
182 }
183
184 static int simple_id_to_gadget(struct usb_gadget_id *gadget_id,
185                                struct usb_gadget **_gadget)
186 {
187         struct usb_gadget *gadget;
188         int n_configs;
189         /* zero terminates */
190         int functions[2][sizeof(gadget_id->function_mask)*8];
191         int n_functions;
192         struct usb_function **funcs;
193         int idx, i, j;
194         int ret;
195
196         if (!gadget_id || !_gadget)
197                 return -EINVAL;
198
199         ret = alloc_default_gadget(&gadget);
200         if (ret)
201                 goto out;
202
203         /*
204          * Currently all gadgets use inly single configuration but
205          * slp-gadget is capable to handle two of them
206          *
207          * Order of interfaces in configuration is significant
208          * so in this switch we sort our functions in a correct order
209          */
210         switch (gadget_id->function_mask) {
211         case USB_FUNCTION_SDB:
212                 n_configs = 1;
213                 functions[0][0] = USB_FUNCTION_SDB;
214                 functions[0][1] = 0;
215                 gadget->attrs.idProduct = 0x685d;
216                 break;
217         case USB_FUNCTION_MTP:
218                 n_configs = 1;
219                 functions[0][0] = USB_FUNCTION_MTP;
220                 functions[0][1] = 0;
221                 gadget->attrs.idProduct = 0x6860;
222                 break;
223         case USB_FUNCTION_RNDIS:
224                 n_configs = 1;
225                 functions[0][0] = USB_FUNCTION_RNDIS;
226                 functions[0][1] = 0;
227                 gadget->attrs.idProduct = 0x6863;
228                 break;
229         case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB:
230                 n_configs = 1;
231                 functions[0][0] = USB_FUNCTION_MTP;
232                 functions[0][1] = USB_FUNCTION_ACM;
233                 functions[0][2] = USB_FUNCTION_SDB;
234                 functions[0][3] = 0;
235                 gadget->attrs.idProduct = 0x6860;
236                 break;
237         case USB_FUNCTION_MTP | USB_FUNCTION_ACM | USB_FUNCTION_SDB
238                 | USB_FUNCTION_DIAG:
239                 n_configs = 1;
240                 functions[0][0] = USB_FUNCTION_MTP;
241                 functions[0][1] = USB_FUNCTION_ACM;
242                 functions[0][2] = USB_FUNCTION_SDB;
243                 functions[0][3] = USB_FUNCTION_DIAG;
244                 functions[0][4] = 0;
245                 gadget->attrs.idProduct = 0x6860;
246                 break;
247         case USB_FUNCTION_RNDIS | USB_FUNCTION_SDB:
248                 n_configs = 1;
249                 functions[0][0] = USB_FUNCTION_RNDIS;
250                 functions[0][1] = USB_FUNCTION_SDB;
251                 functions[0][2] = 0;
252                 gadget->attrs.idProduct = 0x6864;
253                 break;
254         case USB_FUNCTION_RNDIS | USB_FUNCTION_SDB | USB_FUNCTION_ACM | USB_FUNCTION_DIAG:
255                 n_configs = 1;
256                 functions[0][0] = USB_FUNCTION_RNDIS;
257                 functions[0][1] = USB_FUNCTION_SDB;
258                 functions[0][2] = USB_FUNCTION_ACM;
259                 functions[0][3] = USB_FUNCTION_DIAG;
260                 functions[0][4] = 0;
261                 gadget->attrs.idProduct = 0x6864;
262                 break;
263         case USB_FUNCTION_RNDIS | USB_FUNCTION_DIAG:
264                 n_configs = 1;
265                 functions[0][0] = USB_FUNCTION_RNDIS;
266                 functions[0][1] = USB_FUNCTION_DIAG;
267                 functions[0][2] = 0;
268                 gadget->attrs.idProduct = 0x6864;
269                 break;
270         case USB_FUNCTION_ACM | USB_FUNCTION_SDB | USB_FUNCTION_DM:
271                 n_configs = 1;
272                 functions[0][0] = USB_FUNCTION_ACM;
273                 functions[0][1] = USB_FUNCTION_SDB;
274                 functions[0][2] = USB_FUNCTION_DM;
275                 functions[0][3] = 0;
276                 gadget->attrs.idProduct = 0x6860;
277                 break;
278         case USB_FUNCTION_DIAG | USB_FUNCTION_ACM | USB_FUNCTION_RMNET:
279                 n_configs = 1;
280                 functions[0][0] = USB_FUNCTION_DIAG;
281                 functions[0][1] = USB_FUNCTION_ACM;
282                 functions[0][2] = USB_FUNCTION_RMNET;
283                 functions[0][3] = 0;
284                 gadget->attrs.idProduct = 0x685d;
285                 break;
286         };
287
288         if (n_configs > 2) {
289                 ret = -EINVAL;
290                 goto free_gadget;
291         }
292
293         n_functions = __builtin_popcount(gadget_id->function_mask);
294
295         funcs = calloc(n_functions + 1, sizeof(*funcs));
296         if (!funcs) {
297                 ret = -ENOMEM;
298                 goto free_gadget;
299         }
300
301         gadget->funcs = funcs;
302
303         idx = 0;
304         for (i = 0; i < ARRAY_SIZE(_available_funcs); ++i) {
305                 int func_id = 1 << i;
306
307                 if (!(gadget_id->function_mask & func_id))
308                         continue;
309
310                 ret = _available_funcs[i]->clone(_available_funcs[i],
311                         gadget->funcs + idx);
312                 if (ret)
313                         goto free_functions;
314                 ++idx;
315         }
316
317         for (j = 0; j < n_configs; ++j) {
318                 struct usb_configuration *config;
319                 int n_funcs_in_config;
320
321                 for (i = 0; functions[j][i]; ++i);
322                 n_funcs_in_config = i;
323
324                 ret = alloc_default_config(&config);
325                 if (ret)
326                         goto free_configs;
327
328                 gadget->configs[j] = config;
329                 config->funcs = calloc(n_funcs_in_config + 1,
330                                                        sizeof(void *));
331                 if (!config->funcs)
332                         goto free_configs;
333
334                 for (i = 0; functions[j][i]; ++i)
335                         config->funcs[i] = find_func(gadget, functions[j][i]);
336         }
337
338         *_gadget = gadget;
339         return 0;
340 free_configs:
341 free_functions:
342 free_gadget:
343         simple_cleanup_gadget(gadget);
344 out:
345         return ret;
346 }
347
348 static int simple_translator_open(struct hw_info *info,
349                 const char *id, struct hw_common **common)
350 {
351         struct usb_gadget_translator *simple_translator;
352
353         if (!info || !common)
354                 return -EINVAL;
355
356         simple_translator = zalloc(sizeof(*simple_translator));
357         if (!simple_translator)
358                 return -ENOMEM;
359
360         simple_translator->common.info = info;
361         simple_translator->id_to_gadget = simple_id_to_gadget;
362         simple_translator->cleanup_gadget = simple_cleanup_gadget;
363
364         *common = &simple_translator->common;
365         return 0;
366 }
367
368 static int simple_translator_close(struct hw_common *common)
369 {
370         struct usb_gadget_translator *simple_translator;
371
372         if (!common)
373                 return -EINVAL;
374
375         simple_translator = container_of(common, struct usb_gadget_translator,
376                                          common);
377
378         free(simple_translator);
379         return 0;
380 }
381
382 HARDWARE_MODULE_STRUCTURE = {
383         .magic = HARDWARE_INFO_TAG,
384         .hal_version = HARDWARE_INFO_VERSION,
385         .device_version = USB_GADGET_DEVICE_VERSION,
386         .id = USB_GADGET_DEVICE_ID,
387         .name = "simple_translator",
388         .open = simple_translator_open,
389         .close = simple_translator_close,
390 };
391
392 #endif