USB: fix Coding Style.
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc_otg_310 / common_port / dwc_cc.c
1 _otg_/* =========================================================================
2  * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
3  * $Revision: #4 $
4  * $Date: 2010/11/04 $
5  * $Change: 1621692 $
6  *
7  * Synopsys Portability Library Software and documentation
8  * (hereinafter, "Software") is an Unsupported proprietary work of
9  * Synopsys, Inc. unless otherwise expressly agreed to in writing
10  * between Synopsys and you.
11  *
12  * The Software IS NOT an item of Licensed Software or Licensed Product
13  * under any End User Software License Agreement or Agreement for
14  * Licensed Product with Synopsys or any supplement thereto. You are
15  * permitted to use and redistribute this Software in source and binary
16  * forms, with or without modification, provided that redistributions
17  * of source code must retain this notice. You may not view, use,
18  * disclose, copy or distribute this file or any information contained
19  * herein except pursuant to this license grant from Synopsys. If you
20  * do not agree with this notice, including the disclaimer below, then
21  * you are not authorized to use the Software.
22  *
23  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
24  * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
27  * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
31  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
33  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
34  * DAMAGE.
35  * ========================================================================= */
36 #ifdef DWC_CCLIB
37
38 #include "dwc_cc.h"
39
40 typedef struct dwc_cc {
41         uint32_t uid;
42         uint8_t chid[16];
43         uint8_t cdid[16];
44         uint8_t ck[16];
45         uint8_t *name;
46         uint8_t length;
47         DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
48 } dwc_cc_t;
49
50 DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
51
52 /** The main structure for CC management.  */
53 struct dwc_cc_if {
54         dwc_mutex_t *mutex;
55         char *filename;
56
57         unsigned is_host:1;
58
59         dwc_notifier_t *notifier;
60
61         struct context_list list;
62 };
63
64 #ifdef DEBUG
65 static inline void dump_bytes(char *name, uint8_t *bytes, int len)
66 {
67         int i;
68         DWC_PRINTF("%s: ", name);
69         for (i = 0; i < len; i++) {
70                 DWC_PRINTF("%02x ", bytes[i]);
71         }
72         DWC_PRINTF("\n");
73 }
74 #else
75 #define dump_bytes(x...)
76 #endif
77
78 static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
79 {
80         dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
81         if (!cc) {
82                 return NULL;
83         }
84         DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
85
86         if (name) {
87                 cc->length = length;
88                 cc->name = dwc_alloc(mem_ctx, length);
89                 if (!cc->name) {
90                         dwc_free(mem_ctx, cc);
91                         return NULL;
92                 }
93
94                 DWC_MEMCPY(cc->name, name, length);
95         }
96
97         return cc;
98 }
99
100 static void free_cc(void *mem_ctx, dwc_cc_t *cc)
101 {
102         if (cc->name) {
103                 dwc_free(mem_ctx, cc->name);
104         }
105         dwc_free(mem_ctx, cc);
106 }
107
108 static uint32_t next_uid(dwc_cc_if_t *cc_if)
109 {
110         uint32_t uid = 0;
111         dwc_cc_t *cc;
112         DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
113                 if (cc->uid > uid) {
114                         uid = cc->uid;
115                 }
116         }
117
118         if (uid == 0) {
119                 uid = 255;
120         }
121
122         return uid + 1;
123 }
124
125 static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
126 {
127         dwc_cc_t *cc;
128         DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
129                 if (cc->uid == uid) {
130                         return cc;
131                 }
132         }
133         return NULL;
134 }
135
136 static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
137 {
138         unsigned int size = 0;
139         dwc_cc_t *cc;
140         DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
141                 size += (48 + 1);
142                 if (cc->name) {
143                         size += cc->length;
144                 }
145         }
146         return size;
147 }
148
149 static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
150 {
151         uint32_t uid = 0;
152         dwc_cc_t *cc;
153
154         DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
155                 if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
156                         uid = cc->uid;
157                         break;
158                 }
159         }
160         return uid;
161 }
162 static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
163 {
164         uint32_t uid = 0;
165         dwc_cc_t *cc;
166
167         DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
168                 if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
169                         uid = cc->uid;
170                         break;
171                 }
172         }
173         return uid;
174 }
175
176 /* Internal cc_add */
177 static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
178                       uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
179 {
180         dwc_cc_t *cc;
181         uint32_t uid;
182
183         if (cc_if->is_host) {
184                 uid = cc_match_cdid(cc_if, cdid);
185         } else {
186                 uid = cc_match_chid(cc_if, chid);
187         }
188
189         if (uid) {
190                 DWC_DEBUG("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
191                 cc = cc_find(cc_if, uid);
192         } else {
193                 cc = alloc_cc(mem_ctx, name, length);
194                 cc->uid = next_uid(cc_if);
195                 DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
196         }
197
198         DWC_MEMCPY(&(cc->chid[0]), chid, 16);
199         DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
200         DWC_MEMCPY(&(cc->ck[0]), ck, 16);
201
202         DWC_DEBUG("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
203         dump_bytes("CHID", cc->chid, 16);
204         dump_bytes("CDID", cc->cdid, 16);
205         dump_bytes("CK", cc->ck, 16);
206         return cc->uid;
207 }
208
209 /* Internal cc_clear */
210 static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
211 {
212         while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
213                 dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
214                 DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
215                 free_cc(mem_ctx, cc);
216         }
217 }
218
219 dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
220                              dwc_notifier_t *notifier, unsigned is_host)
221 {
222         dwc_cc_if_t *cc_if = NULL;
223
224         /* Allocate a common_cc_if structure */
225         cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
226
227         if (!cc_if)
228                 return NULL;
229
230 #if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
231         DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
232 #else
233         cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
234 #endif
235         if (!cc_if->mutex) {
236                 dwc_free(mem_ctx, cc_if);
237                 return NULL;
238         }
239
240         DWC_CIRCLEQ_INIT(&cc_if->list);
241         cc_if->is_host = is_host;
242         cc_if->notifier = notifier;
243         return cc_if;
244 }
245
246 void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
247 {
248 #if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
249         DWC_MUTEX_FREE(cc_if->mutex);
250 #else
251         dwc_mutex_free(mtx_ctx, cc_if->mutex);
252 #endif
253         cc_clear(mem_ctx, cc_if);
254         dwc_free(mem_ctx, cc_if);
255 }
256
257 static void cc_changed(dwc_cc_if_t *cc_if)
258 {
259         if (cc_if->notifier) {
260                 dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
261         }
262 }
263
264 void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
265 {
266         DWC_MUTEX_LOCK(cc_if->mutex);
267         cc_clear(mem_ctx, cc_if);
268         DWC_MUTEX_UNLOCK(cc_if->mutex);
269         cc_changed(cc_if);
270 }
271
272 int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
273                    uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
274 {
275         uint32_t uid;
276
277         DWC_MUTEX_LOCK(cc_if->mutex);
278         uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
279         DWC_MUTEX_UNLOCK(cc_if->mutex);
280         cc_changed(cc_if);
281
282         return uid;
283 }
284
285 void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
286                    uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
287 {
288         dwc_cc_t *cc;
289
290         DWC_DEBUG("Change connection context %d", id);
291
292         DWC_MUTEX_LOCK(cc_if->mutex);
293         cc = cc_find(cc_if, id);
294         if (!cc) {
295                 DWC_ERROR("Uid %d not found in cc list\n", id);
296                 DWC_MUTEX_UNLOCK(cc_if->mutex);
297                 return;
298         }
299
300         if (chid) {
301                 DWC_MEMCPY(&(cc->chid[0]), chid, 16);
302         }
303         if (cdid) {
304                 DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
305         }
306         if (ck) {
307                 DWC_MEMCPY(&(cc->ck[0]), ck, 16);
308         }
309
310         if (name) {
311                 if (cc->name) {
312                         dwc_free(mem_ctx, cc->name);
313                 }
314                 cc->name = dwc_alloc(mem_ctx, length);
315                 if (!cc->name) {
316                         DWC_ERROR("Out of memory in dwc_cc_change()\n");
317                         DWC_MUTEX_UNLOCK(cc_if->mutex);
318                         return;
319                 }
320                 cc->length = length;
321                 DWC_MEMCPY(cc->name, name, length);
322         }
323
324         DWC_MUTEX_UNLOCK(cc_if->mutex);
325
326         cc_changed(cc_if);
327
328         DWC_DEBUG("Changed connection context id=%d\n", id);
329         dump_bytes("New CHID", cc->chid, 16);
330         dump_bytes("New CDID", cc->cdid, 16);
331         dump_bytes("New CK", cc->ck, 16);
332 }
333
334 void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
335 {
336         dwc_cc_t *cc;
337
338         DWC_DEBUG("Removing connection context %d", id);
339
340         DWC_MUTEX_LOCK(cc_if->mutex);
341         cc = cc_find(cc_if, id);
342         if (!cc) {
343                 DWC_ERROR("Uid %d not found in cc list\n", id);
344                 DWC_MUTEX_UNLOCK(cc_if->mutex);
345                 return;
346         }
347
348         DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
349         DWC_MUTEX_UNLOCK(cc_if->mutex);
350         free_cc(mem_ctx, cc);
351
352         cc_changed(cc_if);
353 }
354
355 uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
356 {
357         uint8_t *buf, *x;
358         uint8_t zero = 0;
359         dwc_cc_t *cc;
360
361         DWC_MUTEX_LOCK(cc_if->mutex);
362         *length = cc_data_size(cc_if);
363         if (!(*length)) {
364                 DWC_MUTEX_UNLOCK(cc_if->mutex);
365                 return NULL;
366         }
367
368         DWC_DEBUG("Creating data for saving (length=%d)", *length);
369
370         buf = dwc_alloc(mem_ctx, *length);
371         if (!buf) {
372                 *length = 0;
373                 DWC_MUTEX_UNLOCK(cc_if->mutex);
374                 return NULL;
375         }
376
377         x = buf;
378         DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
379                 DWC_MEMCPY(x, cc->chid, 16);
380                 x += 16;
381                 DWC_MEMCPY(x, cc->cdid, 16);
382                 x += 16;
383                 DWC_MEMCPY(x, cc->ck, 16);
384                 x += 16;
385                 if (cc->name) {
386                         DWC_MEMCPY(x, &cc->length, 1);
387                         x += 1;
388                         DWC_MEMCPY(x, cc->name, cc->length);
389                         x += cc->length;
390                 } else {
391                         DWC_MEMCPY(x, &zero, 1);
392                         x += 1;
393                 }
394         }
395         DWC_MUTEX_UNLOCK(cc_if->mutex);
396
397         return buf;
398 }
399
400 void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
401 {
402         uint8_t name_length;
403         uint8_t *name;
404         uint8_t *chid;
405         uint8_t *cdid;
406         uint8_t *ck;
407         uint32_t i = 0;
408
409         DWC_MUTEX_LOCK(cc_if->mutex);
410         cc_clear(mem_ctx, cc_if);
411
412         while (i < length) {
413                 chid = &data[i];
414                 i += 16;
415                 cdid = &data[i];
416                 i += 16;
417                 ck = &data[i];
418                 i += 16;
419
420                 name_length = data[i];
421                 i++;
422
423                 if (name_length) {
424                         name = &data[i];
425                         i += name_length;
426                 } else {
427                         name = NULL;
428                 }
429
430                 /* check to see if we haven't overflown the buffer */
431                 if (i > length) {
432                         DWC_ERROR("Data format error while attempting to load CCs "
433                                   "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
434                         break;
435                 }
436
437                 cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
438         }
439         DWC_MUTEX_UNLOCK(cc_if->mutex);
440
441         cc_changed(cc_if);
442 }
443
444 uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
445 {
446         uint32_t uid = 0;
447
448         DWC_MUTEX_LOCK(cc_if->mutex);
449         uid = cc_match_chid(cc_if, chid);
450         DWC_MUTEX_UNLOCK(cc_if->mutex);
451         return uid;
452 }
453 uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
454 {
455         uint32_t uid = 0;
456
457         DWC_MUTEX_LOCK(cc_if->mutex);
458         uid = cc_match_cdid(cc_if, cdid);
459         DWC_MUTEX_UNLOCK(cc_if->mutex);
460         return uid;
461 }
462
463 uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
464 {
465         uint8_t *ck = NULL;
466         dwc_cc_t *cc;
467
468         DWC_MUTEX_LOCK(cc_if->mutex);
469         cc = cc_find(cc_if, id);
470         if (cc) {
471                 ck = cc->ck;
472         }
473         DWC_MUTEX_UNLOCK(cc_if->mutex);
474
475         return ck;
476
477 }
478
479 uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
480 {
481         uint8_t *retval = NULL;
482         dwc_cc_t *cc;
483
484         DWC_MUTEX_LOCK(cc_if->mutex);
485         cc = cc_find(cc_if, id);
486         if (cc) {
487                 retval = cc->chid;
488         }
489         DWC_MUTEX_UNLOCK(cc_if->mutex);
490
491         return retval;
492 }
493
494 uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
495 {
496         uint8_t *retval = NULL;
497         dwc_cc_t *cc;
498
499         DWC_MUTEX_LOCK(cc_if->mutex);
500         cc = cc_find(cc_if, id);
501         if (cc) {
502                 retval = cc->cdid;
503         }
504         DWC_MUTEX_UNLOCK(cc_if->mutex);
505
506         return retval;
507 }
508
509 uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
510 {
511         uint8_t *retval = NULL;
512         dwc_cc_t *cc;
513
514         DWC_MUTEX_LOCK(cc_if->mutex);
515         *length = 0;
516         cc = cc_find(cc_if, id);
517         if (cc) {
518                 *length = cc->length;
519                 retval = cc->name;
520         }
521         DWC_MUTEX_UNLOCK(cc_if->mutex);
522
523         return retval;
524 }
525
526 #endif  /* DWC_CCLIB */