diff options
Diffstat (limited to 'drivers/isdn/hardware/eicon/mntfunc.c')
-rw-r--r-- | drivers/isdn/hardware/eicon/mntfunc.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/drivers/isdn/hardware/eicon/mntfunc.c b/drivers/isdn/hardware/eicon/mntfunc.c new file mode 100644 index 000000000000..a564b7560031 --- /dev/null +++ b/drivers/isdn/hardware/eicon/mntfunc.c | |||
@@ -0,0 +1,370 @@ | |||
1 | /* $Id: mntfunc.c,v 1.19.6.4 2005/01/31 12:22:20 armin Exp $ | ||
2 | * | ||
3 | * Driver for Eicon DIVA Server ISDN cards. | ||
4 | * Maint module | ||
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 | |||
14 | #include "platform.h" | ||
15 | #include "di_defs.h" | ||
16 | #include "divasync.h" | ||
17 | #include "debug_if.h" | ||
18 | |||
19 | extern char *DRIVERRELEASE_MNT; | ||
20 | |||
21 | #define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR) | ||
22 | #define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG) | ||
23 | |||
24 | extern void DIVA_DIDD_Read(void *, int); | ||
25 | |||
26 | static dword notify_handle; | ||
27 | static DESCRIPTOR DAdapter; | ||
28 | static DESCRIPTOR MAdapter; | ||
29 | static DESCRIPTOR MaintDescriptor = | ||
30 | { IDI_DIMAINT, 0, 0, (IDI_CALL) diva_maint_prtComp }; | ||
31 | |||
32 | extern int diva_os_copy_to_user(void *os_handle, void __user *dst, | ||
33 | const void *src, int length); | ||
34 | extern int diva_os_copy_from_user(void *os_handle, void *dst, | ||
35 | const void __user *src, int length); | ||
36 | |||
37 | static void no_printf(unsigned char *x, ...) | ||
38 | { | ||
39 | /* dummy debug function */ | ||
40 | } | ||
41 | |||
42 | #include "debuglib.c" | ||
43 | |||
44 | /* | ||
45 | * DIDD callback function | ||
46 | */ | ||
47 | static void *didd_callback(void *context, DESCRIPTOR * adapter, | ||
48 | int removal) | ||
49 | { | ||
50 | if (adapter->type == IDI_DADAPTER) { | ||
51 | DBG_ERR(("cb: Change in DAdapter ? Oops ?.")); | ||
52 | } else if (adapter->type == IDI_DIMAINT) { | ||
53 | if (removal) { | ||
54 | DbgDeregister(); | ||
55 | memset(&MAdapter, 0, sizeof(MAdapter)); | ||
56 | dprintf = no_printf; | ||
57 | } else { | ||
58 | memcpy(&MAdapter, adapter, sizeof(MAdapter)); | ||
59 | dprintf = (DIVA_DI_PRINTF) MAdapter.request; | ||
60 | DbgRegister("MAINT", DRIVERRELEASE_MNT, DBG_DEFAULT); | ||
61 | } | ||
62 | } else if ((adapter->type > 0) && (adapter->type < 16)) { | ||
63 | if (removal) { | ||
64 | diva_mnt_remove_xdi_adapter(adapter); | ||
65 | } else { | ||
66 | diva_mnt_add_xdi_adapter(adapter); | ||
67 | } | ||
68 | } | ||
69 | return (NULL); | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * connect to didd | ||
74 | */ | ||
75 | static int DIVA_INIT_FUNCTION connect_didd(void) | ||
76 | { | ||
77 | int x = 0; | ||
78 | int dadapter = 0; | ||
79 | IDI_SYNC_REQ req; | ||
80 | DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS]; | ||
81 | |||
82 | DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table)); | ||
83 | |||
84 | for (x = 0; x < MAX_DESCRIPTORS; x++) { | ||
85 | if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */ | ||
86 | dadapter = 1; | ||
87 | memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter)); | ||
88 | req.didd_notify.e.Req = 0; | ||
89 | req.didd_notify.e.Rc = | ||
90 | IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; | ||
91 | req.didd_notify.info.callback = (void *)didd_callback; | ||
92 | req.didd_notify.info.context = NULL; | ||
93 | DAdapter.request((ENTITY *) & req); | ||
94 | if (req.didd_notify.e.Rc != 0xff) | ||
95 | return (0); | ||
96 | notify_handle = req.didd_notify.info.handle; | ||
97 | /* Register MAINT (me) */ | ||
98 | req.didd_add_adapter.e.Req = 0; | ||
99 | req.didd_add_adapter.e.Rc = | ||
100 | IDI_SYNC_REQ_DIDD_ADD_ADAPTER; | ||
101 | req.didd_add_adapter.info.descriptor = | ||
102 | (void *) &MaintDescriptor; | ||
103 | DAdapter.request((ENTITY *) & req); | ||
104 | if (req.didd_add_adapter.e.Rc != 0xff) | ||
105 | return (0); | ||
106 | } else if ((DIDD_Table[x].type > 0) | ||
107 | && (DIDD_Table[x].type < 16)) { | ||
108 | diva_mnt_add_xdi_adapter(&DIDD_Table[x]); | ||
109 | } | ||
110 | } | ||
111 | return (dadapter); | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * disconnect from didd | ||
116 | */ | ||
117 | static void DIVA_EXIT_FUNCTION disconnect_didd(void) | ||
118 | { | ||
119 | IDI_SYNC_REQ req; | ||
120 | |||
121 | req.didd_notify.e.Req = 0; | ||
122 | req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY; | ||
123 | req.didd_notify.info.handle = notify_handle; | ||
124 | DAdapter.request((ENTITY *) & req); | ||
125 | |||
126 | req.didd_remove_adapter.e.Req = 0; | ||
127 | req.didd_remove_adapter.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER; | ||
128 | req.didd_remove_adapter.info.p_request = | ||
129 | (IDI_CALL) MaintDescriptor.request; | ||
130 | DAdapter.request((ENTITY *) & req); | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * read/write maint | ||
135 | */ | ||
136 | int maint_read_write(void __user *buf, int count) | ||
137 | { | ||
138 | byte data[128]; | ||
139 | dword cmd, id, mask; | ||
140 | int ret = 0; | ||
141 | |||
142 | if (count < (3 * sizeof(dword))) | ||
143 | return (-EFAULT); | ||
144 | |||
145 | if (diva_os_copy_from_user(NULL, (void *) &data[0], | ||
146 | buf, 3 * sizeof(dword))) { | ||
147 | return (-EFAULT); | ||
148 | } | ||
149 | |||
150 | cmd = *(dword *) & data[0]; /* command */ | ||
151 | id = *(dword *) & data[4]; /* driver id */ | ||
152 | mask = *(dword *) & data[8]; /* mask or size */ | ||
153 | |||
154 | switch (cmd) { | ||
155 | case DITRACE_CMD_GET_DRIVER_INFO: | ||
156 | if ((ret = diva_get_driver_info(id, data, sizeof(data))) > 0) { | ||
157 | if ((count < ret) || diva_os_copy_to_user | ||
158 | (NULL, buf, (void *) &data[0], ret)) | ||
159 | ret = -EFAULT; | ||
160 | } else { | ||
161 | ret = -EINVAL; | ||
162 | } | ||
163 | break; | ||
164 | |||
165 | case DITRACE_READ_DRIVER_DBG_MASK: | ||
166 | if ((ret = diva_get_driver_dbg_mask(id, (byte *) data)) > 0) { | ||
167 | if ((count < ret) || diva_os_copy_to_user | ||
168 | (NULL, buf, (void *) &data[0], ret)) | ||
169 | ret = -EFAULT; | ||
170 | } else { | ||
171 | ret = -ENODEV; | ||
172 | } | ||
173 | break; | ||
174 | |||
175 | case DITRACE_WRITE_DRIVER_DBG_MASK: | ||
176 | if ((ret = diva_set_driver_dbg_mask(id, mask)) <= 0) { | ||
177 | ret = -ENODEV; | ||
178 | } | ||
179 | break; | ||
180 | |||
181 | /* | ||
182 | Filter commands will ignore the ID due to fact that filtering affects | ||
183 | the B- channel and Audio Tap trace levels only. Also MAINT driver will | ||
184 | select the right trace ID by itself | ||
185 | */ | ||
186 | case DITRACE_WRITE_SELECTIVE_TRACE_FILTER: | ||
187 | if (!mask) { | ||
188 | ret = diva_set_trace_filter (1, "*"); | ||
189 | } else if (mask < sizeof(data)) { | ||
190 | if (diva_os_copy_from_user(NULL, data, (char __user *)buf+12, mask)) { | ||
191 | ret = -EFAULT; | ||
192 | } else { | ||
193 | ret = diva_set_trace_filter ((int)mask, data); | ||
194 | } | ||
195 | } else { | ||
196 | ret = -EINVAL; | ||
197 | } | ||
198 | break; | ||
199 | |||
200 | case DITRACE_READ_SELECTIVE_TRACE_FILTER: | ||
201 | if ((ret = diva_get_trace_filter (sizeof(data), data)) > 0) { | ||
202 | if (diva_os_copy_to_user (NULL, buf, data, ret)) | ||
203 | ret = -EFAULT; | ||
204 | } else { | ||
205 | ret = -ENODEV; | ||
206 | } | ||
207 | break; | ||
208 | |||
209 | case DITRACE_READ_TRACE_ENTRY:{ | ||
210 | diva_os_spin_lock_magic_t old_irql; | ||
211 | word size; | ||
212 | diva_dbg_entry_head_t *pmsg; | ||
213 | byte *pbuf; | ||
214 | |||
215 | if (!(pbuf = diva_os_malloc(0, mask))) { | ||
216 | return (-ENOMEM); | ||
217 | } | ||
218 | |||
219 | for(;;) { | ||
220 | if (!(pmsg = | ||
221 | diva_maint_get_message(&size, &old_irql))) { | ||
222 | break; | ||
223 | } | ||
224 | if (size > mask) { | ||
225 | diva_maint_ack_message(0, &old_irql); | ||
226 | ret = -EINVAL; | ||
227 | break; | ||
228 | } | ||
229 | ret = size; | ||
230 | memcpy(pbuf, pmsg, size); | ||
231 | diva_maint_ack_message(1, &old_irql); | ||
232 | if ((count < size) || | ||
233 | diva_os_copy_to_user (NULL, buf, (void *) pbuf, size)) | ||
234 | ret = -EFAULT; | ||
235 | break; | ||
236 | } | ||
237 | diva_os_free(0, pbuf); | ||
238 | } | ||
239 | break; | ||
240 | |||
241 | case DITRACE_READ_TRACE_ENTRYS:{ | ||
242 | diva_os_spin_lock_magic_t old_irql; | ||
243 | word size; | ||
244 | diva_dbg_entry_head_t *pmsg; | ||
245 | byte *pbuf = NULL; | ||
246 | int written = 0; | ||
247 | |||
248 | if (mask < 4096) { | ||
249 | ret = -EINVAL; | ||
250 | break; | ||
251 | } | ||
252 | if (!(pbuf = diva_os_malloc(0, mask))) { | ||
253 | return (-ENOMEM); | ||
254 | } | ||
255 | |||
256 | for (;;) { | ||
257 | if (!(pmsg = | ||
258 | diva_maint_get_message(&size, &old_irql))) { | ||
259 | break; | ||
260 | } | ||
261 | if ((size + 8) > mask) { | ||
262 | diva_maint_ack_message(0, &old_irql); | ||
263 | break; | ||
264 | } | ||
265 | /* | ||
266 | Write entry length | ||
267 | */ | ||
268 | pbuf[written++] = (byte) size; | ||
269 | pbuf[written++] = (byte) (size >> 8); | ||
270 | pbuf[written++] = 0; | ||
271 | pbuf[written++] = 0; | ||
272 | /* | ||
273 | Write message | ||
274 | */ | ||
275 | memcpy(&pbuf[written], pmsg, size); | ||
276 | diva_maint_ack_message(1, &old_irql); | ||
277 | written += size; | ||
278 | mask -= (size + 4); | ||
279 | } | ||
280 | pbuf[written++] = 0; | ||
281 | pbuf[written++] = 0; | ||
282 | pbuf[written++] = 0; | ||
283 | pbuf[written++] = 0; | ||
284 | |||
285 | if ((count < written) || diva_os_copy_to_user(NULL, buf, (void *) pbuf, written)) { | ||
286 | ret = -EFAULT; | ||
287 | } else { | ||
288 | ret = written; | ||
289 | } | ||
290 | diva_os_free(0, pbuf); | ||
291 | } | ||
292 | break; | ||
293 | |||
294 | default: | ||
295 | ret = -EINVAL; | ||
296 | } | ||
297 | return (ret); | ||
298 | } | ||
299 | |||
300 | /* | ||
301 | * init | ||
302 | */ | ||
303 | int DIVA_INIT_FUNCTION mntfunc_init(int *buffer_length, void **buffer, | ||
304 | unsigned long diva_dbg_mem) | ||
305 | { | ||
306 | if (*buffer_length < 64) { | ||
307 | *buffer_length = 64; | ||
308 | } | ||
309 | if (*buffer_length > 512) { | ||
310 | *buffer_length = 512; | ||
311 | } | ||
312 | *buffer_length *= 1024; | ||
313 | |||
314 | if (diva_dbg_mem) { | ||
315 | *buffer = (void *) diva_dbg_mem; | ||
316 | } else { | ||
317 | while ((*buffer_length >= (64 * 1024)) | ||
318 | && | ||
319 | (!(*buffer = diva_os_malloc (0, *buffer_length)))) { | ||
320 | *buffer_length -= 1024; | ||
321 | } | ||
322 | |||
323 | if (!*buffer) { | ||
324 | DBG_ERR(("init: Can not alloc trace buffer")); | ||
325 | return (0); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | if (diva_maint_init(*buffer, *buffer_length, (diva_dbg_mem == 0))) { | ||
330 | if (!diva_dbg_mem) { | ||
331 | diva_os_free (0, *buffer); | ||
332 | } | ||
333 | DBG_ERR(("init: maint init failed")); | ||
334 | return (0); | ||
335 | } | ||
336 | |||
337 | if (!connect_didd()) { | ||
338 | DBG_ERR(("init: failed to connect to DIDD.")); | ||
339 | diva_maint_finit(); | ||
340 | if (!diva_dbg_mem) { | ||
341 | diva_os_free (0, *buffer); | ||
342 | } | ||
343 | return (0); | ||
344 | } | ||
345 | return (1); | ||
346 | } | ||
347 | |||
348 | /* | ||
349 | * exit | ||
350 | */ | ||
351 | void DIVA_EXIT_FUNCTION mntfunc_finit(void) | ||
352 | { | ||
353 | void *buffer; | ||
354 | int i = 100; | ||
355 | |||
356 | DbgDeregister(); | ||
357 | |||
358 | while (diva_mnt_shutdown_xdi_adapters() && i--) { | ||
359 | diva_os_sleep(10); | ||
360 | } | ||
361 | |||
362 | disconnect_didd(); | ||
363 | |||
364 | if ((buffer = diva_maint_finit())) { | ||
365 | diva_os_free (0, buffer); | ||
366 | } | ||
367 | |||
368 | memset(&MAdapter, 0, sizeof(MAdapter)); | ||
369 | dprintf = no_printf; | ||
370 | } | ||