usb: gadget: g_ffs: Allow to set bmAttributes of configuration
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / misc / tizen_global_lock.c
1 /*
2  * Tizen Global Lock device driver
3  *
4  * Copyright (C) 2014 Samsung Electronics Co., Ltd.
5  *
6  * Author: YoungJun Cho <yj44.cho@samsung.com>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License version 2, as published
10  * by the Free Software Foundation.
11  */
12
13 #include <linux/device.h>
14 #include <linux/fs.h>
15 #include <linux/hash.h>
16 #include <linux/init.h>
17 #include <linux/jiffies.h>
18 #include <linux/kernel.h>
19 #include <linux/miscdevice.h>
20 #include <linux/module.h>
21 #include <linux/sched.h>
22 #include <linux/slab.h>
23 #include <linux/types.h>
24 #include <linux/uaccess.h>
25
26 #include "tizen_global_lock.h"
27
28 #define TGL_DEV_NAME            "tgl"
29
30 #define TGL_HASH_BITS           4
31 #define TGL_HASH_BUCKETS        (1 << TGL_HASH_BITS)
32
33 #define TGL_DEFAULT_TIMEOUT_MS  1000
34
35 /**
36  * struct tgl_device - tgl device structure
37  * @dev: (misc )device pointer
38  * @heads: hash heads for global node data
39  * @lock: lock for hash heads
40  */
41 static struct tgl_device {
42         struct device *dev;
43
44         struct hlist_head heads[TGL_HASH_BUCKETS];
45         struct mutex lock;
46 } tgl;
47
48 /**
49  * struct tgl_session - tgl session structure
50  * @heads: hash heads for session node data
51  * @locked_heads: hash heads for locked session node data
52  * @lock: lock for hash heads
53  */
54 struct tgl_session {
55         struct hlist_head heads[TGL_HASH_BUCKETS];
56         struct hlist_head locked_heads[TGL_HASH_BUCKETS];
57         struct mutex lock;
58 };
59
60 /**
61  * struct tgl_data - tgl data structure
62  * @kref: reference count
63  * @key: key for hash table
64  * @type: lock type
65  * @cnt: lock cnt
66  * @owner: the last owner's tgid for debug
67  * @timeout_ms: timeout for waiting event
68  * @q: waiting event queue for lock
69  * @list: waiting list
70  * @lock: lock for waiting list
71  * @data1: user data 1
72  * @data2: user data 2
73  */
74 struct tgl_data {
75         struct kref kref;
76
77         unsigned int key;
78         atomic_t type;
79         atomic_t cnt;
80         pid_t owner;
81
82         unsigned int timeout_ms;
83         wait_queue_head_t q;
84         struct list_head list;
85         struct mutex lock;
86
87         unsigned int data1;
88         unsigned int data2;
89 };
90
91 /**
92  * struct tgl_node - tgl node structure
93  * @kref: reference count
94  * @node: hash node for data
95  * @data: struct tgl_data pointer
96  */
97 struct tgl_node {
98         struct kref kref;
99
100         struct hlist_node node;
101
102         struct tgl_data *data;
103 };
104
105 /**
106  * struct tgl_wait_node - tgl wait node structure
107  * @node: node for wait list
108  * @session: struct tgl_session pointer
109  */
110 struct tgl_wait_node {
111         struct list_head node;
112         struct tgl_session *session;
113 };
114
115 static inline unsigned int tgl_hash_idx(unsigned int key)
116 {
117         return hash_32(key, TGL_HASH_BITS);
118 }
119
120 static inline void tgl_set_type(struct tgl_data *data, enum tgl_type_data type)
121 {
122         atomic_set(&data->type, (int)type);
123 }
124
125 static inline bool tgl_is_type_none(struct tgl_data *data)
126 {
127         return (atomic_read(&data->type) == (int)TGL_TYPE_NONE);
128 }
129
130 static inline bool tgl_is_type_read(struct tgl_data *data)
131 {
132         return (atomic_read(&data->type) == (int)TGL_TYPE_READ);
133 }
134
135 static inline bool tgl_is_locked(struct tgl_data *data)
136 {
137         return (atomic_read(&data->cnt) != 0);
138 }
139
140 static inline void tgl_lock_get(struct tgl_data *data)
141 {
142         atomic_inc(&data->cnt);
143 }
144
145 static inline void tgl_lock_put(struct tgl_data *data)
146 {
147         atomic_dec(&data->cnt);
148 }
149
150 static struct tgl_data *tgl_create_data(struct tgl_reg_data *reg_data)
151 {
152         struct tgl_data *data;
153
154         data = kzalloc(sizeof(*data), GFP_KERNEL);
155         if (!data)
156                 return NULL;
157
158         kref_init(&data->kref);
159
160         data->key = reg_data->key;
161         data->timeout_ms = reg_data->timeout_ms ? reg_data->timeout_ms :
162                                 TGL_DEFAULT_TIMEOUT_MS;
163
164         mutex_init(&data->lock);
165         init_waitqueue_head(&data->q);
166         INIT_LIST_HEAD(&data->list);
167
168         return data;
169 }
170
171 static void tgl_release_data(struct kref *kref)
172 {
173         struct tgl_data *data = container_of(kref, struct tgl_data, kref);
174
175         mutex_destroy(&data->lock);
176         kfree(data);
177 }
178
179 static void tgl_data_put(struct tgl_data *data)
180 {
181         kref_put(&data->kref, tgl_release_data);
182 }
183
184 static struct tgl_node *tgl_create_node(struct tgl_data *data)
185 {
186         struct tgl_node *node;
187
188         node = kzalloc(sizeof(*node), GFP_KERNEL);
189         if (!node)
190                 return NULL;
191
192         kref_init(&node->kref);
193
194         INIT_HLIST_NODE(&node->node);
195
196         node->data = data;
197
198         return node;
199 }
200
201 static void tgl_node_get(struct tgl_node *node)
202 {
203         kref_get(&node->kref);
204 }
205
206 static void tgl_release_node(struct kref *kref)
207 {
208         struct tgl_node *node = container_of(kref, struct tgl_node, kref);
209
210         hlist_del(&node->node);
211         kfree(node);
212 }
213
214 static int tgl_node_put(struct tgl_node *node)
215 {
216         return kref_put(&node->kref, tgl_release_node);
217 }
218
219 static int tgl_add_data(struct hlist_head *heads, struct mutex *lock,
220                         struct tgl_data *data)
221 {
222         struct tgl_node *node;
223         struct hlist_head *head = &heads[tgl_hash_idx(data->key)];
224
225         node = tgl_create_node(data);
226         if (!node) {
227                 dev_err(tgl.dev, "%s: failed to create node data[%u]\n",
228                         __func__, data->key);
229                 return -ENOMEM;
230         }
231
232         if (lock)
233                 mutex_lock(lock);
234
235         hlist_add_head(&node->node, head);
236
237         if (lock)
238                 mutex_unlock(lock);
239
240         return 0;
241 }
242
243 static int tgl_remove_data(struct hlist_head *heads, struct mutex *lock,
244                                 struct tgl_data *data,
245                                 void (*fini)(struct tgl_data *))
246 {
247         struct tgl_node *node;
248         struct tgl_data *tmp_data;
249         struct hlist_head *head = &heads[tgl_hash_idx(data->key)];
250         struct hlist_node *tnode;
251         int ret = -ENOENT;
252
253         if (lock)
254                 mutex_lock(lock);
255
256         hlist_for_each_entry_safe(node, tnode, head, node) {
257                 tmp_data = node->data;
258                 if (tmp_data->key == data->key) {
259                         ret = tgl_node_put(node);
260                         break;
261                 }
262         }
263
264         if ((ret > 0) && fini) {
265                 fini(data);
266                 ret = 0;
267         }
268
269         if (lock)
270                 mutex_unlock(lock);
271
272         return ret;
273 }
274
275 static int tgl_open(struct inode *inode, struct file *file)
276 {
277         struct tgl_session *session;
278         int i;
279
280         session = kzalloc(sizeof(*session), GFP_KERNEL);
281         if (!session)
282                 return -ENOMEM;
283
284         mutex_init(&session->lock);
285         for (i = 0; i < TGL_HASH_BUCKETS; i++) {
286                 INIT_HLIST_HEAD(&session->heads[i]);
287                 INIT_HLIST_HEAD(&session->locked_heads[i]);
288         }
289
290         file->private_data = (void *)session;
291
292         return 0;
293 }
294
295 static void tgl_wakeup_q(struct tgl_data *data)
296 {
297         if (!tgl_is_locked(data)) {
298                 /* reset lock info */
299                 tgl_set_type(data, TGL_TYPE_NONE);
300                 data->owner = 0;
301         }
302
303         /* wake up next waiter */
304         if (waitqueue_active(&data->q))
305                 wake_up(&data->q);
306 }
307
308 static void tgl_remove_wait_node(struct tgl_data *data,
309                                         struct tgl_session *session)
310 {
311         struct tgl_wait_node *wait_node, *twait_node;
312
313         mutex_lock(&data->lock);
314
315         list_for_each_entry_safe(wait_node, twait_node, &data->list, node) {
316                 if (wait_node->session == session) {
317                         list_del(&wait_node->node);
318                         break;
319                 }
320         }
321
322         mutex_unlock(&data->lock);
323 }
324
325 static void tgl_cleanup_data(struct tgl_session *session)
326 {
327         struct tgl_node *node;
328         struct hlist_node *tnode;
329         struct tgl_data *data;
330         int ret, i;
331
332         mutex_lock(&session->lock);
333
334         /* unlock all locked nodes in session */
335         for (i = 0; i < TGL_HASH_BUCKETS; i++) {
336                 hlist_for_each_entry_safe(node, tnode,
337                                                 &session->locked_heads[i],
338                                                 node) {
339                         data = node->data;
340                         do {
341                                 /* for multiple lock */
342                                 tgl_lock_put(data);
343                                 ret = tgl_node_put(node);
344                         } while (!ret);
345
346                         tgl_wakeup_q(data);
347                 }
348         }
349
350         /* remove nodes from session */
351         for (i = 0; i < TGL_HASH_BUCKETS; i++) {
352                 hlist_for_each_entry_safe(node, tnode, &session->heads[i],
353                                                 node) {
354                         data = node->data;
355
356                         /* check waiter */
357                         tgl_remove_wait_node(data, session);
358                         do {
359                                 /* for multiple registration */
360                                 ret = tgl_node_put(node);
361                         } while (!ret);
362
363                         /* remove it from global */
364                         ret = tgl_remove_data(tgl.heads, &tgl.lock, data,
365                                                 tgl_data_put);
366                         if (ret)
367                                 dev_err(tgl.dev,
368                                         "%s: failed to remove data[%u] from "
369                                         "global[%d]\n",
370                                         __func__, data->key, ret);
371                 }
372         }
373
374         mutex_unlock(&session->lock);
375 }
376
377 static int tgl_release(struct inode *inode, struct file *file)
378 {
379         struct tgl_session *session = (struct tgl_session *)file->private_data;
380
381         tgl_cleanup_data(session);
382
383         mutex_destroy(&session->lock);
384         kfree(session);
385
386         file->private_data = NULL;
387
388         return 0;
389 }
390
391 static struct tgl_node *tgl_find_node(struct hlist_head *heads,
392                                         unsigned int key)
393 {
394         struct tgl_node *node, *found = NULL;
395         struct tgl_data *data;
396         struct hlist_head *head = &heads[tgl_hash_idx(key)];
397
398         hlist_for_each_entry(node, head, node) {
399                 data = node->data;
400                 if (data->key == key) {
401                         found = node;
402                         break;
403                 }
404         }
405
406         return found;
407 }
408
409 static int tgl_register(struct tgl_session *session, void __user *arg)
410 {
411         struct tgl_reg_data reg_data;
412         struct tgl_node *node;
413         struct tgl_data *data;
414         int ret;
415
416         if (copy_from_user(&reg_data, (void __user *)arg, sizeof(reg_data)))
417                 return -EFAULT;
418
419         mutex_lock(&session->lock);
420
421         /* check session first for multiple registration */
422         node = tgl_find_node(session->heads, reg_data.key);
423         if (node) {
424                 tgl_node_get(node);
425                 mutex_unlock(&session->lock);
426                 return 0;
427         }
428
429         mutex_unlock(&session->lock);
430
431         /* check global */
432         mutex_lock(&tgl.lock);
433
434         node = tgl_find_node(tgl.heads, reg_data.key);
435         if (!node) {
436                 data = tgl_create_data(&reg_data);
437                 if (!data) {
438                         mutex_unlock(&tgl.lock);
439                         dev_err(tgl.dev, "%s: failed to create data[%u]\n",
440                                 __func__, reg_data.key);
441                         return -ENOMEM;
442                 }
443
444                 ret = tgl_add_data(tgl.heads, NULL, data);
445                 if (ret) {
446                         mutex_unlock(&tgl.lock);
447                         dev_err(tgl.dev,
448                                 "%s: failed to add data[%u] to global[%d]\n",
449                                 __func__, data->key, ret);
450                         tgl_data_put(data);
451                         return ret;
452                 }
453         } else {
454                 tgl_node_get(node);
455                 data = node->data;
456         }
457
458         mutex_unlock(&tgl.lock);
459
460         /* add to session */
461         ret = tgl_add_data(session->heads, &session->lock, data);
462         if (ret) {
463                 int tmp_ret;
464
465                 dev_err(tgl.dev,
466                         "%s: failed to add data[%u] to session[%d]\n",
467                         __func__, data->key, ret);
468                 tmp_ret = tgl_remove_data(tgl.heads, &tgl.lock, data,
469                                                 tgl_data_put);
470                 if (tmp_ret) {
471                         dev_err(tgl.dev,
472                                 "%s: failed to remove data[%u] from "
473                                 "global[%d]\n", __func__, data->key, tmp_ret);
474                 }
475         }
476
477         return ret;
478 }
479
480 static int tgl_unregister(struct tgl_session *session, void __user *arg)
481 {
482         struct tgl_reg_data reg_data;
483         struct tgl_node *node;
484         struct tgl_data *data;
485         int ret;
486
487         if (copy_from_user(&reg_data, (void __user *)arg, sizeof(reg_data)))
488                 return -EFAULT;
489
490         /* check in session */
491         mutex_lock(&session->lock);
492
493         node = tgl_find_node(session->heads, reg_data.key);
494         if (!node) {
495                 mutex_unlock(&session->lock);
496                 dev_err(tgl.dev,
497                         "%s: failed to find node data[%u] in session\n",
498                         __func__, reg_data.key);
499                 return -ENOENT;
500         }
501         data = node->data;
502
503         /* for single registration and locked state */
504         if (atomic_read(&node->kref.refcount) == 1) {
505                 if (tgl_find_node(session->locked_heads, reg_data.key)) {
506                         mutex_unlock(&session->lock);
507                         dev_err(tgl.dev,
508                                 "%s: node data[%u] is in locked session yet\n",
509                                 __func__, reg_data.key);
510                         return -EBUSY;
511                 }
512
513                 /* check waiter */
514                 tgl_remove_wait_node(data, session);
515         }
516
517         /* remove from session */
518         if (tgl_node_put(node)) {
519                 /* remove from global */
520                 ret = tgl_remove_data(tgl.heads, &tgl.lock, data, tgl_data_put);
521                 if (ret) {
522                         mutex_unlock(&session->lock);
523                         dev_err(tgl.dev,
524                                 "%s: failed to remove data[%u] from "
525                                 "global[%d]\n", __func__, reg_data.key, ret);
526                         return ret;
527                 }
528         }
529
530         mutex_unlock(&session->lock);
531
532         return 0;
533 }
534
535 static bool tgl_check_lock_condition(struct tgl_data *data,
536                                         struct tgl_wait_node *wait_node,
537                                         enum tgl_type_data type)
538 {
539         bool ret = false;
540
541         mutex_lock(&data->lock);
542
543         /* FIXME: more generic way */
544         if (&wait_node->node == data->list.next) {
545                 if (
546                         /* unlocked state */
547                         (!tgl_is_locked(data) && tgl_is_type_none(data)) ||
548                         /* read locked state */
549                         (tgl_is_locked(data) && tgl_is_type_read(data) &&
550                                 (type == TGL_TYPE_READ)))
551                         ret = true;
552         }
553
554         mutex_unlock(&data->lock);
555
556         return ret;
557 }
558
559 static int tgl_lock(struct tgl_session *session, void __user *arg)
560 {
561         struct tgl_lock_data lock_data;
562         struct tgl_node *node;
563         struct tgl_data *data;
564         struct tgl_wait_node wait_node;
565         pid_t owner = task_tgid_nr(current);
566         int ret;
567
568         if (copy_from_user(&lock_data, (void __user *)arg, sizeof(lock_data)))
569                 return -EFAULT;
570
571         /* check in session */
572         mutex_lock(&session->lock);
573
574         node = tgl_find_node(session->heads, lock_data.key);
575         if (!node) {
576                 mutex_unlock(&session->lock);
577                 dev_err(tgl.dev,
578                         "%s: failed to find node data[%u] in session\n",
579                         __func__, lock_data.key);
580                 return -ENOENT;
581         }
582         data = node->data;
583
584         /* for multiple lock */
585         if (tgl_is_locked(data) &&
586                 tgl_is_type_read(data) && (lock_data.type == TGL_TYPE_READ)) {
587                 mutex_lock(&data->lock);
588                 /* for no waiter */
589                 if (list_empty(&data->list)) {
590                         mutex_unlock(&data->lock);
591                         tgl_lock_get(data);
592                         data->owner = owner;
593                         goto add_data;
594                 } else
595                         mutex_unlock(&data->lock);
596         }
597
598         /* add to waiter */
599         INIT_LIST_HEAD(&wait_node.node);
600         mutex_lock(&data->lock);
601         list_add_tail(&wait_node.node, &data->list);
602         mutex_unlock(&data->lock);
603
604         mutex_unlock(&session->lock);
605         ret = wait_event_timeout(data->q, tgl_check_lock_condition(data,
606                                                 &wait_node, lock_data.type),
607                                         msecs_to_jiffies(data->timeout_ms));
608         mutex_lock(&session->lock);
609         if (!ret) {
610                 dev_err(tgl.dev,
611                         "%s: timed out to lock with [%u] because of tgid[%d]",
612                         __func__, lock_data.key, data->owner);
613                 mutex_lock(&data->lock);
614                 list_del(&wait_node.node);
615                 mutex_unlock(&data->lock);
616                 tgl_wakeup_q(data);
617                 mutex_unlock(&session->lock);
618                 return -ETIMEDOUT;
619         }
620
621         tgl_lock_get(data);
622
623         /* set lock info */
624         tgl_set_type(data, lock_data.type);
625         data->owner = owner;
626
627         mutex_lock(&data->lock);
628         list_del(&wait_node.node);
629         /* for multiple lock, wake up next waiter */
630         if (tgl_is_type_read(data) && !list_empty(&data->list)) {
631                 mutex_unlock(&data->lock);
632                 if (waitqueue_active(&data->q))
633                         wake_up(&data->q);
634         } else
635                 mutex_unlock(&data->lock);
636
637 add_data:
638         /* add to locked session */
639         node = tgl_find_node(session->locked_heads, data->key);
640         if (!node) {
641                 ret = tgl_add_data(session->locked_heads, NULL, data);
642                 if (ret) {
643                         dev_err(tgl.dev,
644                                 "%s: failed to add data[%u] to locked "
645                                 "session[%d]\n", __func__, data->key, ret);
646                         tgl_lock_put(data);
647                         tgl_wakeup_q(data);
648                         mutex_unlock(&session->lock);
649                         return ret;
650                 }
651         } else
652                 tgl_node_get(node);
653
654         mutex_unlock(&session->lock);
655
656         return 0;
657 }
658
659 static int tgl_unlock(struct tgl_session *session, void __user *arg)
660 {
661         struct tgl_lock_data lock_data;
662         struct tgl_node *node;
663         struct tgl_data *data;
664
665         if (copy_from_user(&lock_data, (void __user *)arg, sizeof(lock_data)))
666                 return -EFAULT;
667
668         /* check in locked session */
669         mutex_lock(&session->lock);
670
671         node = tgl_find_node(session->locked_heads, lock_data.key);
672         if (!node) {
673                 node = tgl_find_node(session->heads, lock_data.key);
674                 if (node) {
675                         /* check waiter */
676                         tgl_remove_wait_node(data, session);
677                         mutex_unlock(&session->lock);
678                         return 0;
679                 }
680
681                 mutex_unlock(&session->lock);
682                 dev_err(tgl.dev,
683                         "%s: failed to find node data[%u] in locked session\n",
684                         __func__, lock_data.key);
685                 return -ENOENT;
686         }
687         data = node->data;
688
689         tgl_lock_put(data);
690
691         /* remove from locked session */
692         if (tgl_node_put(node))
693                 tgl_wakeup_q(data);
694
695         mutex_unlock(&session->lock);
696
697         return 0;
698 }
699
700 static int tgl_set_usr_data(struct tgl_session *session, void __user *arg)
701 {
702         struct tgl_usr_data usr_data;
703         struct tgl_node *node;
704         struct tgl_data *data;
705
706         if (copy_from_user(&usr_data, (void __user *)arg, sizeof(usr_data)))
707                 return -EFAULT;
708
709         mutex_lock(&session->lock);
710
711         node = tgl_find_node(session->heads, usr_data.key);
712         if (!node) {
713                 mutex_unlock(&session->lock);
714                 dev_err(tgl.dev,
715                         "%s: failed to find node data[%u] in session\n",
716                         __func__, usr_data.key);
717                 return -ENOENT;
718         }
719         data = node->data;
720
721         data->data1 = usr_data.data1;
722         data->data2 = usr_data.data2;
723
724         mutex_unlock(&session->lock);
725
726         return 0;
727 }
728
729 static int tgl_get_usr_data(struct tgl_session *session, void __user *arg)
730 {
731         struct tgl_usr_data usr_data;
732         struct tgl_node *node;
733         struct tgl_data *data;
734
735         if (copy_from_user(&usr_data, (void __user *)arg, sizeof(usr_data)))
736                 return -EFAULT;
737
738         mutex_lock(&session->lock);
739
740         node = tgl_find_node(session->heads, usr_data.key);
741         if (!node) {
742                 mutex_unlock(&session->lock);
743                 dev_err(tgl.dev,
744                         "%s: failed to find node data[%u] in session\n",
745                         __func__, usr_data.key);
746                 return -ENOENT;
747         }
748         data = node->data;
749
750         usr_data.data1 = data->data1;
751         usr_data.data2 = data->data2;
752         usr_data.status = tgl_is_locked(data) ? TGL_STATUS_LOCKED :
753                                 TGL_STATUS_UNLOCKED;
754
755         mutex_unlock(&session->lock);
756
757         if (copy_to_user(arg, &usr_data, sizeof(usr_data)))
758                 return -EFAULT;
759
760         return 0;
761 }
762
763 static long tgl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
764 {
765         struct tgl_session *session = (struct tgl_session *)file->private_data;
766         int ret;
767
768         switch (cmd) {
769         case TGL_IOCTL_REGISTER:
770                 ret = tgl_register(session, (void __user *)arg);
771                 if (ret)
772                         dev_err(tgl.dev,
773                                 "%s: failed to regsiter[%d]\n", __func__, ret);
774                 break;
775         case TGL_IOCTL_UNREGISTER:
776                 ret = tgl_unregister(session, (void __user *)arg);
777                 if (ret)
778                         dev_err(tgl.dev,
779                                 "%s: failed to unregsiter[%d]\n",
780                                 __func__, ret);
781                 break;
782         case TGL_IOCTL_LOCK:
783                 ret = tgl_lock(session, (void __user *)arg);
784                 if (ret)
785                         dev_err(tgl.dev,
786                                 "%s: failed to lock[%d]\n", __func__, ret);
787                 break;
788         case TGL_IOCTL_UNLOCK:
789                 ret = tgl_unlock(session, (void __user *)arg);
790                 if (ret)
791                         dev_err(tgl.dev,
792                                 "%s: failed to unlock[%d]\n", __func__, ret);
793                 break;
794         case TGL_IOCTL_SET_DATA:
795                 ret = tgl_set_usr_data(session, (void __user *)arg);
796                 if (ret)
797                         dev_err(tgl.dev,
798                                 "%s: failed to set user data[%d]\n",
799                                 __func__, ret);
800                 break;
801         case TGL_IOCTL_GET_DATA:
802                 ret = tgl_get_usr_data(session, (void __user *)arg);
803                 if (ret)
804                         dev_err(tgl.dev,
805                                 "%s: failed to get user data[%d]\n",
806                                 __func__, ret);
807                 break;
808         default:
809                 dev_err(tgl.dev,
810                         "%s: failed to call ioctl: tgid[%d]\n",
811                         __func__, task_tgid_nr(current));
812                 ret = -ENOTTY;
813                 break;
814         }
815
816         return ret;
817 }
818
819 static const struct file_operations tgl_fops = {
820         .owner = THIS_MODULE,
821         .open = tgl_open,
822         .release = tgl_release,
823         .unlocked_ioctl = tgl_ioctl,
824 #ifdef CONFIG_COMPAT
825         .compat_ioctl = tgl_ioctl,
826 #endif
827 };
828
829 static struct miscdevice tgl_misc_device = {
830         .minor = MISC_DYNAMIC_MINOR,
831         .name = TGL_DEV_NAME,
832         .fops = &tgl_fops,
833 };
834
835 static int __init tgl_init(void)
836 {
837         int ret, i;
838
839         ret = misc_register(&tgl_misc_device);
840         if (ret) {
841                 pr_err("%s: failed to register misc device[%d]\n",
842                         __func__, ret);
843                 return ret;
844         }
845         tgl.dev = tgl_misc_device.this_device;
846
847         mutex_init(&tgl.lock);
848         for (i = 0; i < TGL_HASH_BUCKETS; i++)
849                 INIT_HLIST_HEAD(&tgl.heads[i]);
850
851         return 0;
852 }
853 module_init(tgl_init);
854
855 static void __exit tgl_exit(void)
856 {
857         mutex_destroy(&tgl.lock);
858         misc_deregister(&tgl_misc_device);
859 }
860 module_exit(tgl_exit);
861
862 MODULE_DESCRIPTION("Tizen Global Lock");
863 MODULE_AUTHOR("YoungJun Cho <yj44.cho@samsung.com>");
864 MODULE_LICENSE("GPL v2");