Merge branch 'for-rmk' of git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa...
[linux-2.6] / sound / pci / ctxfi / ctimap.c
1 /**
2  * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
3  *
4  * This source file is released under GPL v2 license (no other versions).
5  * See the COPYING file included in the main directory of this source
6  * distribution for the license terms and conditions.
7  *
8  * @File        ctimap.c
9  *
10  * @Brief
11  * This file contains the implementation of generic input mapper operations
12  * for input mapper management.
13  *
14  * @Author      Liu Chun
15  * @Date        May 23 2008
16  *
17  */
18
19 #include "ctimap.h"
20 #include <linux/slab.h>
21
22 int input_mapper_add(struct list_head *mappers, struct imapper *entry,
23                      int (*map_op)(void *, struct imapper *), void *data)
24 {
25         struct list_head *pos, *pre, *head;
26         struct imapper *pre_ent, *pos_ent;
27
28         head = mappers;
29
30         if (list_empty(head)) {
31                 entry->next = entry->addr;
32                 map_op(data, entry);
33                 list_add(&entry->list, head);
34                 return 0;
35         }
36
37         list_for_each(pos, head) {
38                 pos_ent = list_entry(pos, struct imapper, list);
39                 if (pos_ent->slot > entry->slot) {
40                         /* found a position in list */
41                         break;
42                 }
43         }
44
45         if (pos != head) {
46                 pre = pos->prev;
47                 if (pre == head)
48                         pre = head->prev;
49
50                 __list_add(&entry->list, pos->prev, pos);
51         } else {
52                 pre = head->prev;
53                 pos = head->next;
54                 list_add_tail(&entry->list, head);
55         }
56
57         pre_ent = list_entry(pre, struct imapper, list);
58         pos_ent = list_entry(pos, struct imapper, list);
59
60         entry->next = pos_ent->addr;
61         map_op(data, entry);
62         pre_ent->next = entry->addr;
63         map_op(data, pre_ent);
64
65         return 0;
66 }
67
68 int input_mapper_delete(struct list_head *mappers, struct imapper *entry,
69                      int (*map_op)(void *, struct imapper *), void *data)
70 {
71         struct list_head *next, *pre, *head;
72         struct imapper *pre_ent, *next_ent;
73
74         head = mappers;
75
76         if (list_empty(head))
77                 return 0;
78
79         pre = (entry->list.prev == head) ? head->prev : entry->list.prev;
80         next = (entry->list.next == head) ? head->next : entry->list.next;
81
82         if (pre == &entry->list) {
83                 /* entry is the only one node in mappers list */
84                 entry->next = entry->addr = entry->user = entry->slot = 0;
85                 map_op(data, entry);
86                 list_del(&entry->list);
87                 return 0;
88         }
89
90         pre_ent = list_entry(pre, struct imapper, list);
91         next_ent = list_entry(next, struct imapper, list);
92
93         pre_ent->next = next_ent->addr;
94         map_op(data, pre_ent);
95         list_del(&entry->list);
96
97         return 0;
98 }
99
100 void free_input_mapper_list(struct list_head *head)
101 {
102         struct imapper *entry;
103         struct list_head *pos;
104
105         while (!list_empty(head)) {
106                 pos = head->next;
107                 list_del(pos);
108                 entry = list_entry(pos, struct imapper, list);
109                 kfree(entry);
110         }
111 }
112