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