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 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 __init 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 __exit 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 __init 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 __exit 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} 371