blob: a564b7560031dfaac28ad8d7924370f513acb79f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $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
19extern 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
24extern void DIVA_DIDD_Read(void *, int);
25
26static dword notify_handle;
27static DESCRIPTOR DAdapter;
28static DESCRIPTOR MAdapter;
29static DESCRIPTOR MaintDescriptor =
30 { IDI_DIMAINT, 0, 0, (IDI_CALL) diva_maint_prtComp };
31
32extern int diva_os_copy_to_user(void *os_handle, void __user *dst,
33 const void *src, int length);
34extern int diva_os_copy_from_user(void *os_handle, void *dst,
35 const void __user *src, int length);
36
37static void no_printf(unsigned char *x, ...)
38{
39 /* dummy debug function */
40}
41
42#include "debuglib.c"
43
44/*
45 * DIDD callback function
46 */
47static 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 */
75static 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 */
117static 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 */
136int 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 */
303int 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 */
351void 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}