1
2#include <linux/kernel.h>
3#include <linux/module.h>
4#include <linux/isdn/capilli.h>
5
6#define DBG(format, arg...) do { \
7printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
8} while (0)
9
10struct capilib_msgidqueue {
11	struct capilib_msgidqueue *next;
12	u16 msgid;
13};
14
15struct capilib_ncci {
16	struct list_head list;
17	u16 applid;
18	u32 ncci;
19	u32 winsize;
20	int   nmsg;
21	struct capilib_msgidqueue *msgidqueue;
22	struct capilib_msgidqueue *msgidlast;
23	struct capilib_msgidqueue *msgidfree;
24	struct capilib_msgidqueue msgidpool[CAPI_MAXDATAWINDOW];
25};
26
27// ---------------------------------------------------------------------------
28// NCCI Handling
29
30static inline void mq_init(struct capilib_ncci * np)
31{
32	u_int i;
33	np->msgidqueue = NULL;
34	np->msgidlast = NULL;
35	np->nmsg = 0;
36	memset(np->msgidpool, 0, sizeof(np->msgidpool));
37	np->msgidfree = &np->msgidpool[0];
38	for (i = 1; i < np->winsize; i++) {
39		np->msgidpool[i].next = np->msgidfree;
40		np->msgidfree = &np->msgidpool[i];
41	}
42}
43
44static inline int mq_enqueue(struct capilib_ncci * np, u16 msgid)
45{
46	struct capilib_msgidqueue *mq;
47	if ((mq = np->msgidfree) == 0)
48		return 0;
49	np->msgidfree = mq->next;
50	mq->msgid = msgid;
51	mq->next = NULL;
52	if (np->msgidlast)
53		np->msgidlast->next = mq;
54	np->msgidlast = mq;
55	if (!np->msgidqueue)
56		np->msgidqueue = mq;
57	np->nmsg++;
58	return 1;
59}
60
61static inline int mq_dequeue(struct capilib_ncci * np, u16 msgid)
62{
63	struct capilib_msgidqueue **pp;
64	for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
65		if ((*pp)->msgid == msgid) {
66			struct capilib_msgidqueue *mq = *pp;
67			*pp = mq->next;
68			if (mq == np->msgidlast)
69				np->msgidlast = NULL;
70			mq->next = np->msgidfree;
71			np->msgidfree = mq;
72			np->nmsg--;
73			return 1;
74		}
75	}
76	return 0;
77}
78
79void capilib_new_ncci(struct list_head *head, u16 applid, u32 ncci, u32 winsize)
80{
81	struct capilib_ncci *np;
82
83	np = kmalloc(sizeof(*np), GFP_ATOMIC);
84	if (!np) {
85		printk(KERN_WARNING "capilib_new_ncci: no memory.\n");
86		return;
87	}
88	if (winsize > CAPI_MAXDATAWINDOW) {
89		printk(KERN_ERR "capi_new_ncci: winsize %d too big\n",
90		       winsize);
91		winsize = CAPI_MAXDATAWINDOW;
92	}
93	np->applid = applid;
94	np->ncci = ncci;
95	np->winsize = winsize;
96	mq_init(np);
97	list_add_tail(&np->list, head);
98	DBG("kcapi: appl %d ncci 0x%x up", applid, ncci);
99}
100
101EXPORT_SYMBOL(capilib_new_ncci);
102
103void capilib_free_ncci(struct list_head *head, u16 applid, u32 ncci)
104{
105	struct list_head *l;
106	struct capilib_ncci *np;
107
108	list_for_each(l, head) {
109		np = list_entry(l, struct capilib_ncci, list);
110		if (np->applid != applid)
111			continue;
112		if (np->ncci != ncci)
113			continue;
114		printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", applid, ncci);
115		list_del(&np->list);
116		kfree(np);
117		return;
118	}
119	printk(KERN_ERR "capilib_free_ncci: ncci 0x%x not found\n", ncci);
120}
121
122EXPORT_SYMBOL(capilib_free_ncci);
123
124void capilib_release_appl(struct list_head *head, u16 applid)
125{
126	struct list_head *l, *n;
127	struct capilib_ncci *np;
128
129	list_for_each_safe(l, n, head) {
130		np = list_entry(l, struct capilib_ncci, list);
131		if (np->applid != applid)
132			continue;
133		printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down\n", applid, np->ncci);
134		list_del(&np->list);
135		kfree(np);
136	}
137}
138
139EXPORT_SYMBOL(capilib_release_appl);
140
141void capilib_release(struct list_head *head)
142{
143	struct list_head *l, *n;
144	struct capilib_ncci *np;
145
146	list_for_each_safe(l, n, head) {
147		np = list_entry(l, struct capilib_ncci, list);
148		printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down\n", np->applid, np->ncci);
149		list_del(&np->list);
150		kfree(np);
151	}
152}
153
154EXPORT_SYMBOL(capilib_release);
155
156u16 capilib_data_b3_req(struct list_head *head, u16 applid, u32 ncci, u16 msgid)
157{
158	struct list_head *l;
159	struct capilib_ncci *np;
160
161	list_for_each(l, head) {
162		np = list_entry(l, struct capilib_ncci, list);
163		if (np->applid != applid)
164			continue;
165		if (np->ncci != ncci)
166			continue;
167
168		if (mq_enqueue(np, msgid) == 0)
169			return CAPI_SENDQUEUEFULL;
170
171		return CAPI_NOERROR;
172	}
173	printk(KERN_ERR "capilib_data_b3_req: ncci 0x%x not found\n", ncci);
174	return CAPI_NOERROR;
175}
176
177EXPORT_SYMBOL(capilib_data_b3_req);
178
179void capilib_data_b3_conf(struct list_head *head, u16 applid, u32 ncci, u16 msgid)
180{
181	struct list_head *l;
182	struct capilib_ncci *np;
183
184	list_for_each(l, head) {
185		np = list_entry(l, struct capilib_ncci, list);
186		if (np->applid != applid)
187			continue;
188		if (np->ncci != ncci)
189			continue;
190
191		if (mq_dequeue(np, msgid) == 0) {
192			printk(KERN_ERR "kcapi: msgid %hu ncci 0x%x not on queue\n",
193			       msgid, ncci);
194		}
195		return;
196	}
197	printk(KERN_ERR "capilib_data_b3_conf: ncci 0x%x not found\n", ncci);
198}
199
200EXPORT_SYMBOL(capilib_data_b3_conf);
201