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 000000000..1cd9affb6 --- /dev/null +++ b/drivers/isdn/hardware/eicon/mntfunc.c @@ -0,0 +1,370 @@ +/* $Id: mntfunc.c,v 1.19.6.4 2005/01/31 12:22:20 armin Exp $ + * + * Driver for Eicon DIVA Server ISDN cards. + * Maint module + * + * Copyright 2000-2003 by Armin Schindler (mac@melware.de) + * Copyright 2000-2003 Cytronics & Melware (info@melware.de) + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + */ + + +#include "platform.h" +#include "di_defs.h" +#include "divasync.h" +#include "debug_if.h" + +extern char *DRIVERRELEASE_MNT; + +#define DBG_MINIMUM (DL_LOG + DL_FTL + DL_ERR) +#define DBG_DEFAULT (DBG_MINIMUM + DL_XLOG + DL_REG) + +extern void DIVA_DIDD_Read(void *, int); + +static dword notify_handle; +static DESCRIPTOR DAdapter; +static DESCRIPTOR MAdapter; +static DESCRIPTOR MaintDescriptor = +{ IDI_DIMAINT, 0, 0, (IDI_CALL) diva_maint_prtComp }; + +extern int diva_os_copy_to_user(void *os_handle, void __user *dst, + const void *src, int length); +extern int diva_os_copy_from_user(void *os_handle, void *dst, + const void __user *src, int length); + +static void no_printf(unsigned char *x, ...) +{ + /* dummy debug function */ +} + +#include "debuglib.c" + +/* + * DIDD callback function + */ +static void *didd_callback(void *context, DESCRIPTOR *adapter, + int removal) +{ + if (adapter->type == IDI_DADAPTER) { + DBG_ERR(("cb: Change in DAdapter ? Oops ?.")); + } else if (adapter->type == IDI_DIMAINT) { + if (removal) { + DbgDeregister(); + memset(&MAdapter, 0, sizeof(MAdapter)); + dprintf = no_printf; + } else { + memcpy(&MAdapter, adapter, sizeof(MAdapter)); + dprintf = (DIVA_DI_PRINTF) MAdapter.request; + DbgRegister("MAINT", DRIVERRELEASE_MNT, DBG_DEFAULT); + } + } else if ((adapter->type > 0) && (adapter->type < 16)) { + if (removal) { + diva_mnt_remove_xdi_adapter(adapter); + } else { + diva_mnt_add_xdi_adapter(adapter); + } + } + return (NULL); +} + +/* + * connect to didd + */ +static int __init connect_didd(void) +{ + int x = 0; + int dadapter = 0; + IDI_SYNC_REQ req; + DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS]; + + DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table)); + + for (x = 0; x < MAX_DESCRIPTORS; x++) { + if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */ + dadapter = 1; + memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter)); + req.didd_notify.e.Req = 0; + req.didd_notify.e.Rc = + IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY; + req.didd_notify.info.callback = (void *)didd_callback; + req.didd_notify.info.context = NULL; + DAdapter.request((ENTITY *)&req); + if (req.didd_notify.e.Rc != 0xff) + return (0); + notify_handle = req.didd_notify.info.handle; + /* Register MAINT (me) */ + req.didd_add_adapter.e.Req = 0; + req.didd_add_adapter.e.Rc = + IDI_SYNC_REQ_DIDD_ADD_ADAPTER; + req.didd_add_adapter.info.descriptor = + (void *) &MaintDescriptor; + DAdapter.request((ENTITY *)&req); + if (req.didd_add_adapter.e.Rc != 0xff) + return (0); + } else if ((DIDD_Table[x].type > 0) + && (DIDD_Table[x].type < 16)) { + diva_mnt_add_xdi_adapter(&DIDD_Table[x]); + } + } + return (dadapter); +} + +/* + * disconnect from didd + */ +static void __exit disconnect_didd(void) +{ + IDI_SYNC_REQ req; + + req.didd_notify.e.Req = 0; + req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY; + req.didd_notify.info.handle = notify_handle; + DAdapter.request((ENTITY *)&req); + + req.didd_remove_adapter.e.Req = 0; + req.didd_remove_adapter.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER; + req.didd_remove_adapter.info.p_request = + (IDI_CALL) MaintDescriptor.request; + DAdapter.request((ENTITY *)&req); +} + +/* + * read/write maint + */ +int maint_read_write(void __user *buf, int count) +{ + byte data[128]; + dword cmd, id, mask; + int ret = 0; + + if (count < (3 * sizeof(dword))) + return (-EFAULT); + + if (diva_os_copy_from_user(NULL, (void *) &data[0], + buf, 3 * sizeof(dword))) { + return (-EFAULT); + } + + cmd = *(dword *)&data[0]; /* command */ + id = *(dword *)&data[4]; /* driver id */ + mask = *(dword *)&data[8]; /* mask or size */ + + switch (cmd) { + case DITRACE_CMD_GET_DRIVER_INFO: + if ((ret = diva_get_driver_info(id, data, sizeof(data))) > 0) { + if ((count < ret) || diva_os_copy_to_user + (NULL, buf, (void *) &data[0], ret)) + ret = -EFAULT; + } else { + ret = -EINVAL; + } + break; + + case DITRACE_READ_DRIVER_DBG_MASK: + if ((ret = diva_get_driver_dbg_mask(id, (byte *) data)) > 0) { + if ((count < ret) || diva_os_copy_to_user + (NULL, buf, (void *) &data[0], ret)) + ret = -EFAULT; + } else { + ret = -ENODEV; + } + break; + + case DITRACE_WRITE_DRIVER_DBG_MASK: + if ((ret = diva_set_driver_dbg_mask(id, mask)) <= 0) { + ret = -ENODEV; + } + break; + + /* + Filter commands will ignore the ID due to fact that filtering affects + the B- channel and Audio Tap trace levels only. Also MAINT driver will + select the right trace ID by itself + */ + case DITRACE_WRITE_SELECTIVE_TRACE_FILTER: + if (!mask) { + ret = diva_set_trace_filter(1, "*"); + } else if (mask < sizeof(data)) { + if (diva_os_copy_from_user(NULL, data, (char __user *)buf + 12, mask)) { + ret = -EFAULT; + } else { + ret = diva_set_trace_filter((int)mask, data); + } + } else { + ret = -EINVAL; + } + break; + + case DITRACE_READ_SELECTIVE_TRACE_FILTER: + if ((ret = diva_get_trace_filter(sizeof(data), data)) > 0) { + if (diva_os_copy_to_user(NULL, buf, data, ret)) + ret = -EFAULT; + } else { + ret = -ENODEV; + } + break; + + case DITRACE_READ_TRACE_ENTRY:{ + diva_os_spin_lock_magic_t old_irql; + word size; + diva_dbg_entry_head_t *pmsg; + byte *pbuf; + + if (!(pbuf = diva_os_malloc(0, mask))) { + return (-ENOMEM); + } + + for (;;) { + if (!(pmsg = + diva_maint_get_message(&size, &old_irql))) { + break; + } + if (size > mask) { + diva_maint_ack_message(0, &old_irql); + ret = -EINVAL; + break; + } + ret = size; + memcpy(pbuf, pmsg, size); + diva_maint_ack_message(1, &old_irql); + if ((count < size) || + diva_os_copy_to_user(NULL, buf, (void *) pbuf, size)) + ret = -EFAULT; + break; + } + diva_os_free(0, pbuf); + } + break; + + case DITRACE_READ_TRACE_ENTRYS:{ + diva_os_spin_lock_magic_t old_irql; + word size; + diva_dbg_entry_head_t *pmsg; + byte *pbuf = NULL; + int written = 0; + + if (mask < 4096) { + ret = -EINVAL; + break; + } + if (!(pbuf = diva_os_malloc(0, mask))) { + return (-ENOMEM); + } + + for (;;) { + if (!(pmsg = + diva_maint_get_message(&size, &old_irql))) { + break; + } + if ((size + 8) > mask) { + diva_maint_ack_message(0, &old_irql); + break; + } + /* + Write entry length + */ + pbuf[written++] = (byte) size; + pbuf[written++] = (byte) (size >> 8); + pbuf[written++] = 0; + pbuf[written++] = 0; + /* + Write message + */ + memcpy(&pbuf[written], pmsg, size); + diva_maint_ack_message(1, &old_irql); + written += size; + mask -= (size + 4); + } + pbuf[written++] = 0; + pbuf[written++] = 0; + pbuf[written++] = 0; + pbuf[written++] = 0; + + if ((count < written) || diva_os_copy_to_user(NULL, buf, (void *) pbuf, written)) { + ret = -EFAULT; + } else { + ret = written; + } + diva_os_free(0, pbuf); + } + break; + + default: + ret = -EINVAL; + } + return (ret); +} + +/* + * init + */ +int __init mntfunc_init(int *buffer_length, void **buffer, + unsigned long diva_dbg_mem) +{ + if (*buffer_length < 64) { + *buffer_length = 64; + } + if (*buffer_length > 512) { + *buffer_length = 512; + } + *buffer_length *= 1024; + + if (diva_dbg_mem) { + *buffer = (void *) diva_dbg_mem; + } else { + while ((*buffer_length >= (64 * 1024)) + && + (!(*buffer = diva_os_malloc(0, *buffer_length)))) { + *buffer_length -= 1024; + } + + if (!*buffer) { + DBG_ERR(("init: Can not alloc trace buffer")); + return (0); + } + } + + if (diva_maint_init(*buffer, *buffer_length, (diva_dbg_mem == 0))) { + if (!diva_dbg_mem) { + diva_os_free(0, *buffer); + } + DBG_ERR(("init: maint init failed")); + return (0); + } + + if (!connect_didd()) { + DBG_ERR(("init: failed to connect to DIDD.")); + diva_maint_finit(); + if (!diva_dbg_mem) { + diva_os_free(0, *buffer); + } + return (0); + } + return (1); +} + +/* + * exit + */ +void __exit mntfunc_finit(void) +{ + void *buffer; + int i = 100; + + DbgDeregister(); + + while (diva_mnt_shutdown_xdi_adapters() && i--) { + diva_os_sleep(10); + } + + disconnect_didd(); + + if ((buffer = diva_maint_finit())) { + diva_os_free(0, buffer); + } + + memset(&MAdapter, 0, sizeof(MAdapter)); + dprintf = no_printf; +} |