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