blob: 1b5d72f780e206b98d6d25924e715c601dcfbdab [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/* ============================================================================== */
29/* Double-link list definitions (adapted from Atheros SDIO stack) */
30/* */
31/* Author(s): ="Atheros" */
32/* ============================================================================== */
33
34#ifndef __DL_LIST_H___
35#define __DL_LIST_H___
36
37#define A_CONTAINING_STRUCT(address, struct_type, field_name) \
38 ((struct_type *)((char *)(address) - (char *)(&((struct_type *)0)->field_name)))
39
40/* list functions */
41/* pointers for the list */
42typedef struct _DL_LIST {
43 struct _DL_LIST *pPrev;
44 struct _DL_LIST *pNext;
45} DL_LIST, *PDL_LIST;
46/*
47 * DL_LIST_INIT , initialize doubly linked list
48 */
49#define DL_LIST_INIT(pList) \
50 {(pList)->pPrev = pList; (pList)->pNext = pList; }
51
52/* faster macro to init list and add a single item */
53#define DL_LIST_INIT_AND_ADD(pList,pItem) \
54 { (pList)->pPrev = (pItem); \
55 (pList)->pNext = (pItem); \
56 (pItem)->pNext = (pList); \
57 (pItem)->pPrev = (pList); \
58 }
59
60#define DL_LIST_IS_EMPTY(pList) (((pList)->pPrev == (pList)) && ((pList)->pNext == (pList)))
61#define DL_LIST_GET_ITEM_AT_HEAD(pList) (pList)->pNext
62#define DL_LIST_GET_ITEM_AT_TAIL(pList) (pList)->pPrev
63/*
64 * ITERATE_OVER_LIST pStart is the list, pTemp is a temp list member
65 * NOT: do not use this function if the items in the list are deleted inside the
66 * iteration loop
67 */
68#define ITERATE_OVER_LIST(pStart, pTemp) \
69 for((pTemp) =(pStart)->pNext; pTemp != (pStart); (pTemp) = (pTemp)->pNext)
70
71static __inline bool dl_list_is_entry_in_list(const DL_LIST *pList,
72 const DL_LIST *pEntry)
73{
74 const DL_LIST *pTmp;
75
76 if (pList == pEntry)
77 return true;
78
79 ITERATE_OVER_LIST(pList, pTmp) {
80 if (pTmp == pEntry) {
81 return true;
82 }
83 }
84
85 return false;
86}
87
88/* safe iterate macro that allows the item to be removed from the list
89 * the iteration continues to the next item in the list
90 */
91#define ITERATE_OVER_LIST_ALLOW_REMOVE(pStart,pItem,st,offset) \
92 { \
93 PDL_LIST pTemp; \
94 pTemp = (pStart)->pNext; \
95 while (pTemp != (pStart)) { \
96 (pItem) = A_CONTAINING_STRUCT(pTemp,st,offset); \
97 pTemp = pTemp->pNext; \
98
99#define ITERATE_IS_VALID(pStart) dl_list_is_entry_in_list(pStart, pTemp)
100#define ITERATE_RESET(pStart) pTemp=(pStart)->pNext
101
102#define ITERATE_END }}
103
104/*
105 * dl_list_insert_tail - insert pAdd to the end of the list
106 */
107static __inline PDL_LIST dl_list_insert_tail(PDL_LIST pList, PDL_LIST pAdd)
108{
109 /* insert at tail */
110 pAdd->pPrev = pList->pPrev;
111 pAdd->pNext = pList;
112 if (pList->pPrev) {
113 pList->pPrev->pNext = pAdd;
114 }
115 pList->pPrev = pAdd;
116 return pAdd;
117}
118
119/*
120 * dl_list_insert_head - insert pAdd into the head of the list
121 */
122static __inline PDL_LIST dl_list_insert_head(PDL_LIST pList, PDL_LIST pAdd)
123{
124 /* insert at head */
125 pAdd->pPrev = pList;
126 pAdd->pNext = pList->pNext;
127 pList->pNext->pPrev = pAdd;
128 pList->pNext = pAdd;
129 return pAdd;
130}
131
132#define DL_ListAdd(pList,pItem) dl_list_insert_head((pList),(pItem))
133/*
134 * dl_list_remove - remove pDel from list
135 */
136static __inline PDL_LIST dl_list_remove(PDL_LIST pDel)
137{
138 if (pDel->pNext != NULL) {
139 pDel->pNext->pPrev = pDel->pPrev;
140 }
141 if (pDel->pPrev != NULL) {
142 pDel->pPrev->pNext = pDel->pNext;
143 }
144
145 /* point back to itself just to be safe, incase remove is called again */
146 pDel->pNext = pDel;
147 pDel->pPrev = pDel;
148 return pDel;
149}
150
151/*
152 * dl_list_remove_item_from_head - get a list item from the head
153 */
154static __inline PDL_LIST dl_list_remove_item_from_head(PDL_LIST pList)
155{
156 PDL_LIST pItem = NULL;
157 if (pList->pNext != pList) {
158 pItem = pList->pNext;
159 /* remove the first item from head */
160 dl_list_remove(pItem);
161 }
162 return pItem;
163}
164
165static __inline PDL_LIST dl_list_remove_item_from_tail(PDL_LIST pList)
166{
167 PDL_LIST pItem = NULL;
168 if (pList->pPrev != pList) {
169 pItem = pList->pPrev;
170 /* remove the item from tail */
171 dl_list_remove(pItem);
172 }
173 return pItem;
174}
175
176/* transfer src list items to the tail of the destination list */
177static __inline void dl_list_transfer_items_to_tail(PDL_LIST pDest, PDL_LIST pSrc)
178{
179 /* only concatenate if src is not empty */
180 if (!DL_LIST_IS_EMPTY(pSrc)) {
181 /* cut out circular list in src and re-attach to end of dest */
182 pSrc->pPrev->pNext = pDest;
183 pSrc->pNext->pPrev = pDest->pPrev;
184 pDest->pPrev->pNext = pSrc->pNext;
185 pDest->pPrev = pSrc->pPrev;
186 /* terminate src list, it is now empty */
187 pSrc->pPrev = pSrc;
188 pSrc->pNext = pSrc;
189 }
190}
191
192/* transfer src list items to the head of the destination list */
193static __inline void dl_list_transfer_items_to_head(PDL_LIST pDest, PDL_LIST pSrc)
194{
195 /* only concatenate if src is not empty */
196 if (!DL_LIST_IS_EMPTY(pSrc)) {
197 /* cut out circular list in src and re-attach to start of dest */
198 pSrc->pNext->pPrev = pDest;
199 pDest->pNext->pPrev = pSrc->pPrev;
200 pSrc->pPrev->pNext = pDest->pNext;
201 pDest->pNext = pSrc->pNext;
202 /* terminate src list, it is now empty */
203 pSrc->pPrev = pSrc;
204 pSrc->pNext = pSrc;
205 }
206}
207
208#endif /* __DL_LIST_H___ */