Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mntfunc.c
Go to the documentation of this file.
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 ([email protected])
7  * Copyright 2000-2003 Cytronics & Melware ([email protected])
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 =
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;
61  }
62  } else if ((adapter->type > 0) && (adapter->type < 16)) {
63  if (removal) {
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 __init connect_didd(void)
76 {
77  int x = 0;
78  int dadapter = 0;
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 =
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 =
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 __exit disconnect_didd(void)
118 {
120 
121  req.didd_notify.e.Req = 0;
123  req.didd_notify.info.handle = notify_handle;
124  DAdapter.request((ENTITY *)&req);
125 
126  req.didd_remove_adapter.e.Req = 0;
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) {
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 
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 
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  */
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 
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 
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 
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  */
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."));
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  */
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 }