diff options
Diffstat (limited to 'drivers/isdn/hardware/eicon/idifunc.c')
-rw-r--r-- | drivers/isdn/hardware/eicon/idifunc.c | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/drivers/isdn/hardware/eicon/idifunc.c b/drivers/isdn/hardware/eicon/idifunc.c new file mode 100644 index 000000000000..4cbc68cf4dba --- /dev/null +++ b/drivers/isdn/hardware/eicon/idifunc.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* $Id: idifunc.c,v 1.14.4.4 2004/08/28 20:03:53 armin Exp $ | ||
2 | * | ||
3 | * Driver for Eicon DIVA Server ISDN cards. | ||
4 | * User Mode IDI Interface | ||
5 | * | ||
6 | * Copyright 2000-2003 by Armin Schindler (mac@melware.de) | ||
7 | * Copyright 2000-2003 Cytronics & Melware (info@melware.de) | ||
8 | * | ||
9 | * This software may be used and distributed according to the terms | ||
10 | * of the GNU General Public License, incorporated herein by reference. | ||
11 | */ | ||
12 | |||
13 | #include "platform.h" | ||
14 | #include "di_defs.h" | ||
15 | #include "divasync.h" | ||
16 | #include "um_xdi.h" | ||
17 | #include "um_idi.h" | ||
18 | |||
19 | #define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR) | ||
20 | #define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG) | ||
21 | |||
22 | extern char *DRIVERRELEASE_IDI; | ||
23 | |||
24 | extern void DIVA_DIDD_Read(void *, int); | ||
25 | extern int diva_user_mode_idi_create_adapter(const DESCRIPTOR *, int); | ||
26 | extern void diva_user_mode_idi_remove_adapter(int); | ||
27 | |||
28 | static dword notify_handle; | ||
29 | static DESCRIPTOR DAdapter; | ||
30 | static DESCRIPTOR MAdapter; | ||
31 | |||
32 | static void no_printf(unsigned char *x, ...) | ||
33 | { | ||
34 | /* dummy debug function */ | ||
35 | } | ||
36 | |||
37 | #include "debuglib.c" | ||
38 | |||
39 | /* | ||
40 | * stop debug | ||
41 | */ | ||
42 | static void stop_dbg(void) | ||
43 | { | ||
44 | DbgDeregister(); | ||
45 | memset(&MAdapter, 0, sizeof(MAdapter)); | ||
46 | dprintf = no_printf; | ||
47 | } | ||
48 | |||
49 | typedef struct _udiva_card { | ||
50 | struct list_head list; | ||
51 | int Id; | ||
52 | DESCRIPTOR d; | ||
53 | } udiva_card; | ||
54 | |||
55 | static LIST_HEAD(cards); | ||
56 | static diva_os_spin_lock_t ll_lock; | ||
57 | |||
58 | /* | ||
59 | * find card in list | ||
60 | */ | ||
61 | static udiva_card *find_card_in_list(DESCRIPTOR * d) | ||
62 | { | ||
63 | udiva_card *card; | ||
64 | struct list_head *tmp; | ||
65 | diva_os_spin_lock_magic_t old_irql; | ||
66 | |||
67 | diva_os_enter_spin_lock(&ll_lock, &old_irql, "find card"); | ||
68 | list_for_each(tmp, &cards) { | ||
69 | card = list_entry(tmp, udiva_card, list); | ||
70 | if (card->d.request == d->request) { | ||
71 | diva_os_leave_spin_lock(&ll_lock, &old_irql, | ||
72 | "find card"); | ||
73 | return (card); | ||
74 | } | ||
75 | } | ||
76 | diva_os_leave_spin_lock(&ll_lock, &old_irql, "find card"); | ||
77 | return ((udiva_card *) NULL); | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * new card | ||
82 | */ | ||
83 | static void um_new_card(DESCRIPTOR * d) | ||
84 | { | ||
85 | int adapter_nr = 0; | ||
86 | udiva_card *card = NULL; | ||
87 | IDI_SYNC_REQ sync_req; | ||
88 | diva_os_spin_lock_magic_t old_irql; | ||
89 | |||
90 | if (!(card = diva_os_malloc(0, sizeof(udiva_card)))) { | ||
91 | DBG_ERR(("cannot get buffer for card")); | ||
92 | return; | ||
93 | } | ||
94 | memcpy(&card->d, d, sizeof(DESCRIPTOR)); | ||
95 | sync_req.xdi_logical_adapter_number.Req = 0; | ||
96 | sync_req.xdi_logical_adapter_number.Rc = | ||
97 | IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER; | ||
98 | card->d.request((ENTITY *) & sync_req); | ||
99 | adapter_nr = | ||
100 | sync_req.xdi_logical_adapter_number.info.logical_adapter_number; | ||
101 | card->Id = adapter_nr; | ||
102 | if (!(diva_user_mode_idi_create_adapter(d, adapter_nr))) { | ||
103 | diva_os_enter_spin_lock(&ll_lock, &old_irql, "add card"); | ||
104 | list_add_tail(&card->list, &cards); | ||
105 | diva_os_leave_spin_lock(&ll_lock, &old_irql, "add card"); | ||
106 | } else { | ||
107 | DBG_ERR(("could not create user mode idi card %d", | ||
108 | adapter_nr)); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * remove card | ||
114 | */ | ||
115 | static void um_remove_card(DESCRIPTOR * d) | ||
116 | { | ||
117 | diva_os_spin_lock_magic_t old_irql; | ||
118 | udiva_card *card = NULL; | ||
119 | |||
120 | if (!(card = find_card_in_list(d))) { | ||
121 | DBG_ERR(("cannot find card to remove")); | ||
122 | return; | ||
123 | } | ||
124 | diva_user_mode_idi_remove_adapter(card->Id); | ||
125 | diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove card"); | ||
126 | list_del(&card->list); | ||
127 | diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove card"); | ||
128 | DBG_LOG(("idi proc entry removed for card %d", card->Id)); | ||
129 | diva_os_free(0, card); | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * remove all adapter | ||
134 | */ | ||
135 | static void DIVA_EXIT_FUNCTION remove_all_idi_proc(void) | ||
136 | { | ||
137 | udiva_card *card; | ||
138 | diva_os_spin_lock_magic_t old_irql; | ||
139 | |||
140 | rescan: | ||
141 | diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove all"); | ||
142 | if (!list_empty(&cards)) { | ||
143 | card = list_entry(cards.next, udiva_card, list); | ||
144 | list_del(&card->list); | ||
145 | diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove all"); | ||
146 | diva_user_mode_idi_remove_adapter(card->Id); | ||
147 | diva_os_free(0, card); | ||
148 | goto rescan; | ||
149 | } | ||
150 | diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove all"); | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * DIDD notify callback | ||
155 | */ | ||
156 | static void *didd_callback(void *context, DESCRIPTOR * adapter, | ||
157 | int removal) | ||
158 | { | ||
159 | if (adapter->type == IDI_DADAPTER) { | ||
160 | DBG_ERR(("Notification about IDI_DADAPTER change ! Oops.")); | ||
161 | return (NULL); | ||
162 | } else if (adapter->type == IDI_DIMAINT) { | ||
163 | if (removal) { | ||
164 | stop_dbg(); | ||
165 | } else { | ||
166 | memcpy(&MAdapter, adapter, sizeof(MAdapter)); | ||
167 | dprintf = (DIVA_DI_PRINTF) MAdapter.request; | ||
168 | DbgRegister("User IDI", DRIVERRELEASE_IDI, DBG_DEFAULT); | ||
169 | } | ||
170 | } else if ((adapter->type > 0) && (adapter->type < 16)) { /* IDI Adapter */ | ||
171 | if (removal) { | ||
172 | um_remove_card(adapter); | ||
173 | } else { | ||
174 | um_new_card(adapter); | ||
175 | } | ||
176 | } | ||
177 | return (NULL); | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * connect DIDD | ||
182 | */ | ||
183 | static int DIVA_INIT_FUNCTION connect_didd(void) | ||
184 | { | ||
185 | int x = 0; | ||
186 | int dadapter = 0; | ||
187 | IDI_SYNC_REQ req; | ||
188 | DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS]; | ||
189 | |||
190 | DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table)); | ||
191 | |||
192 | for (x = 0; x < MAX_DESCRIPTORS; x++) { | ||
193 | if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */ | ||
194 | dadapter = 1; | ||
195 | memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter)); | ||
196 | req.didd_notify.e.Req = 0; | ||
197 | req.didd_notify.e.Rc = | ||
198 | IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; | ||
199 | req.didd_notify.info.callback = (void *)didd_callback; | ||
200 | req.didd_notify.info.context = NULL; | ||
201 | DAdapter.request((ENTITY *) & req); | ||
202 | if (req.didd_notify.e.Rc != 0xff) { | ||
203 | stop_dbg(); | ||
204 | return (0); | ||
205 | } | ||
206 | notify_handle = req.didd_notify.info.handle; | ||
207 | } else if (DIDD_Table[x].type == IDI_DIMAINT) { /* MAINT found */ | ||
208 | memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter)); | ||
209 | dprintf = (DIVA_DI_PRINTF) MAdapter.request; | ||
210 | DbgRegister("User IDI", DRIVERRELEASE_IDI, DBG_DEFAULT); | ||
211 | } else if ((DIDD_Table[x].type > 0) | ||
212 | && (DIDD_Table[x].type < 16)) { /* IDI Adapter found */ | ||
213 | um_new_card(&DIDD_Table[x]); | ||
214 | } | ||
215 | } | ||
216 | |||
217 | if (!dadapter) { | ||
218 | stop_dbg(); | ||
219 | } | ||
220 | |||
221 | return (dadapter); | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * Disconnect from DIDD | ||
226 | */ | ||
227 | static void DIVA_EXIT_FUNCTION disconnect_didd(void) | ||
228 | { | ||
229 | IDI_SYNC_REQ req; | ||
230 | |||
231 | stop_dbg(); | ||
232 | |||
233 | req.didd_notify.e.Req = 0; | ||
234 | req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY; | ||
235 | req.didd_notify.info.handle = notify_handle; | ||
236 | DAdapter.request((ENTITY *) & req); | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * init | ||
241 | */ | ||
242 | int DIVA_INIT_FUNCTION idifunc_init(void) | ||
243 | { | ||
244 | diva_os_initialize_spin_lock(&ll_lock, "idifunc"); | ||
245 | |||
246 | if (diva_user_mode_idi_init()) { | ||
247 | DBG_ERR(("init: init failed.")); | ||
248 | return (0); | ||
249 | } | ||
250 | |||
251 | if (!connect_didd()) { | ||
252 | diva_user_mode_idi_finit(); | ||
253 | DBG_ERR(("init: failed to connect to DIDD.")); | ||
254 | return (0); | ||
255 | } | ||
256 | return (1); | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * finit | ||
261 | */ | ||
262 | void DIVA_EXIT_FUNCTION idifunc_finit(void) | ||
263 | { | ||
264 | diva_user_mode_idi_finit(); | ||
265 | disconnect_didd(); | ||
266 | remove_all_idi_proc(); | ||
267 | } | ||