/* $Id: debugvar.c,v 1.7 2000/02/16 14:56:26 paul Exp $

 * Variable-debugging for isdn4linux.
 *
 * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
 * Copyright 1995 Thinking Objects Software GmbH Wuerzburg
 *
 * This file is part of Isdn4Linux.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Log: debugvar.c,v $
 * Revision 1.7  2000/02/16 14:56:26  paul
 * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers
 *
 * Revision 1.6  1999/04/12 12:33:07  fritz
 * Changes from 2.0 tree.
 *
 * Revision 1.5  1997/02/03 23:34:51  fritz
 * Reformatted
 *
 * Revision 1.4  1996/04/30 07:55:50  fritz
 * Disabled mmap.
 *
 * Revision 1.3  1996/04/28 15:19:23  fritz
 * adapted to new ioctl names.
 *
 * Revision 1.2  1996/01/04 02:46:16  fritz
 * Changed copying policy to GPL.
 *
 * Revision 1.1  1995/12/18  18:22:52  fritz
 * Initial revision
 *
 */

#include <sys/types.h>
#include <sys/fcntl.h>
/* #include <sys/mman.h> */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>

#include <linux/isdn.h>
#include <linux/isdnif.h>

typedef unsigned char uchar;
int mem_fd;

#if 0                           /* Weiss der Teufel, warum das nicht mit mmap geht */
uchar
* mapmem(ulong location, long size)
{
	ulong mmseg;
	ulong mmsize;
	ulong addr;
	ulong offset;

	mmseg = location & 0xffffe000L;
	mmsize = (location - mmseg + size) + 0x1000;
	offset = location - mmseg;
	addr = (ulong) mmap(0, mmsize, PROT_READ, MAP_SHARED, mem_fd, mmseg);
	if ((int) addr == -1) {
		perror("mmap");
		exit(1);
	}
	printf("mmap: loc=%08lx siz=%08lx mseg=%08lx msiz=%08lx ofs=%08lx adr=%08lx\n", location, size, mmseg, mmsize, offset, addr);
	return ((uchar *) (addr + offset));
}
#else
uchar
* mapmem(ulong location, long size)
{
	uchar *buffer;

	if ((buffer = malloc(size))) {
		lseek(mem_fd, location, SEEK_SET);
		read(mem_fd, buffer, size);
	} else {
		perror("malloc");
		exit(1);
	}
	return buffer;
}
#endif

char *
dumpIntArray(int *arr, int count)
{
	static char buf[1024];
	char *p = buf;
	int i;

	for (i = 0; i < count; i++)
		p += sprintf(p, "%d%s", arr[i], (i < (count - 1)) ? ", " : "\0");
	return (buf);
}

char *
dumpCharArray(char *arr, int count)
{
	static char buf[1024];
	char *p = buf;
	int i;

	for (i = 0; i < count; i++)
		p += sprintf(p, "%02x%s", (uchar) arr[i], (i < (count - 1)) ? ", " : "\0");
	return (buf);
}

char *
dumpStringArray(char *arr, int count, int len)
{
	static char buf[1024];
	char *p = buf;
	char *s = arr;
	int i;

	for (i = 0; i < count; s += len, i++)
		p += sprintf(p, "\"%s\"%s", s, (i < (count - 1)) ? ", " : "\0");
	return (buf);
}

void
dumpDriver(ulong drvaddr)
{
	driver *drv = (driver *) mapmem(drvaddr, sizeof(driver));
	isdn_if *ifc = (isdn_if *) mapmem((ulong) drv->interface, sizeof(isdn_if));

	printf("  online     = %08lx\n", drv->online);
	printf("  channels   = %d\n", drv->channels);
	printf("  locks      = %d\n", drv->locks);
	printf("  reject_bus = %d\n", drv->flags & DRV_FLAG_REJBUS);
	printf("  running    = %d\n", drv->flags & DRV_FLAG_RUNNING);
	printf("  loaded     = %d\n", drv->flags & DRV_FLAG_LOADED);
	printf("  maxbufsize = %d\n", drv->maxbufsize);
	printf("  pktcount   = %ld\n", drv->pktcount);
	printf("  stavail    = %d\n", drv->stavail);
	printf("  Interface @%08lx:\n", (ulong) drv->interface);
	printf("    Id(ch)     = %d\n", ifc->channels);
	printf("    maxbufsize = %d\n", ifc->maxbufsize);
	printf("    features   = %08lx\n", ifc->features);
}

void
dumpModem(modem mdm)
{
	int i;
	atemu *atm;
	modem_info *info;

	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
		printf("mdm [%02d]\n", i);
		printf("  msr            = %08x\n", mdm.msr[i]);
		printf("  mlr            = %08x\n", mdm.mlr[i]);
		printf("  refcount       = %d\n", mdm.refcount);
		printf("  online         = %d\n", mdm.online[i]);
		printf("  dialing        = %d\n", mdm.dialing[i]);
		printf("  rcvsched       = %d\n", mdm.rcvsched[i]);
		printf("  ncarrier       = %d\n", mdm.ncarrier[i]);
		printf("  atmodem:\n");
		atm = &mdm.atmodem[i];
		printf("    profile      = \n      %s\n", dumpCharArray(atm->mdmreg, ISDN_MODEM_NUMREG));
		printf("    mdmreg       = \n      %s\n", dumpCharArray(atm->mdmreg, ISDN_MODEM_NUMREG));
		printf("    msn          = \"%s\"\n", atm->msn);
		printf("    mdmcmdl      = %d\n", atm->mdmcmdl);
		printf("    pluscount    = %d\n", atm->pluscount);
		printf("    lastplus     = %08x\n", atm->lastplus);
		printf("    mdmcmd       = \"%s\"\n", atm->mdmcmd);
		printf("  info:\n");
		info = &mdm.info[i];
		printf("    magic        = %08x\n", info->magic);
		printf("    flags        = %08x\n", info->flags);
		printf("    type         = %d\n", info->type);
		printf("    x_char       = %02x\n", info->x_char);
		printf("    close_delay  = %d\n", info->close_delay);
		printf("    MCR          = %08x\n", info->MCR);
		printf("    line         = %d\n", info->line);
		printf("    count        = %d\n", info->count);
		printf("    blocked_open = %d\n", info->blocked_open);
		printf("    session      = %08lx\n", info->session);
		printf("    pgrp         = %08lx\n", info->pgrp);
		printf("    isdn_driver  = %d\n", info->isdn_driver);
		printf("    isdn_channel = %d\n", info->isdn_channel);
		printf("    drv_index    = %d\n", info->drv_index);
		printf("    xmit_size    = %d\n", info->xmit_size);
		printf("    xmit_count   = %d\n", info->xmit_count);
	}
}

void
dumpNetPhone(ulong paddr)
{
	ulong pa = paddr;
	isdn_net_phone *phone;

	while (pa) {
		phone = (isdn_net_phone *) mapmem(pa, sizeof(isdn_net_phone));
		printf("    @%08lx: \"%s\"\n", pa, phone->num);
		pa = (ulong) (phone->next);
	}
}

void
dumpNetDev(ulong devaddr)
{
	ulong nda = devaddr;
	isdn_net_dev *ndev;

	while (nda) {
		ndev = (isdn_net_dev *) mapmem(nda, sizeof(isdn_net_dev));
		printf("Net-Device @%08lx:\n", nda);
		printf("dev. :\n");
		printf("  start        = %d\n", ndev->dev.start);
		printf("  tbusy        = %ld\n", ndev->dev.tbusy);
		printf("  interrupt    = %d\n", ndev->dev.interrupt);
		printf("local. :\n");
		printf("  name         = \"%s\"\n", ndev->local.name);
		printf("  isdn_device  = %d\n", ndev->local.isdn_device);
		printf("  isdn_channel = %d\n", ndev->local.isdn_channel);
		printf("  ppp_minor    = %d\n", ndev->local.ppp_minor);
		printf("  pre_device   = %d\n", ndev->local.pre_device);
		printf("  pre_channel  = %d\n", ndev->local.pre_channel);
		printf("  exclusive    = %d\n", ndev->local.exclusive);
		printf("  flags        = %d\n", ndev->local.flags);
		printf("  dialstate    = %d\n", ndev->local.dialstate);
		printf("  dialretry    = %d\n", ndev->local.dialretry);
		printf("  dialmax      = %d\n", ndev->local.dialmax);
		printf("  msn          = \"%s\"\n", ndev->local.msn);
		printf("  dtimer       = %d\n", ndev->local.dtimer);
		printf("  p_encap      = %d\n", ndev->local.p_encap);
		printf("  l2_proto     = %d\n", ndev->local.l2_proto);
		printf("  l3_proto     = %d\n", ndev->local.l3_proto);
		printf("  huptimer     = %d\n", ndev->local.huptimer);
		printf("  charge       = %d\n", ndev->local.charge);
		printf("  chargetime   = %08x\n", ndev->local.chargetime);
		printf("  hupflags     = %d\n", ndev->local.hupflags);
		printf("  outgoing     = %d\n", ndev->local.outgoing);
		printf("  onhtime      = %d\n", ndev->local.onhtime);
		printf("  chargeint    = %d\n", ndev->local.chargeint);
		printf("  onum         = %d\n", ndev->local.onum);
		printf("  sqfull       = %08x\n", ndev->local.sqfull);
		printf("  sqfull_stamp = %08lx\n", ndev->local.sqfull_stamp);
		printf("  master       = -> %08x\n", (unsigned int) ndev->local.master);
		printf("  slave        = -> %08x\n", (unsigned int) ndev->local.slave);
		if (ndev->local.phone[0]) {
			printf("  phone[in]:\n");
			dumpNetPhone((ulong) ndev->local.phone[0]);
		} else
			printf("  phone[in]    = NULL\n");
		if (ndev->local.phone[1]) {
			printf("  phone[out]:\n");
			dumpNetPhone((ulong) ndev->local.phone[1]);
		} else
			printf("  phone[out]   = NULL\n");
		printf("  dial         = @%08lx\n", (ulong) ndev->local.dial);
		nda = (ulong) (ndev->next);
	}
}

void
main(int argc, char *argv[], char *envp[])
{
	int f;
	int i;
	static isdn_dev *my_isdndev;
	ulong kaddr;

	printf("\nDebugger for isdn and icn Modules\n");
	f = open("/dev/isdnctrl", O_RDONLY);
	if (ioctl(f, IIOCDBGVAR, &kaddr)) {
		perror("ioctl IIOCDBGVAR");
		exit(-1);
	}
	close(f);
	if ((mem_fd = open("/dev/kmem", O_RDWR)) < 0) {
		perror("open /dev/kmem");
		exit(1);
	}
	printf("isdn-main-struct at %08lx (%d):\n", kaddr, sizeof(isdn_dev));
	my_isdndev = (isdn_dev *) mapmem(kaddr, sizeof(isdn_dev));
	printf("isdndev.flags        = %d\n", my_isdndev->flags);
	printf("isdndev.drivers      = %d\n", my_isdndev->drivers);
	printf("isdndev.channels     = %d\n", my_isdndev->channels);
	printf("isdndev.net_verbose  = %d\n", my_isdndev->net_verbose);
	printf("isdndev.modempoll    = %d\n", my_isdndev->modempoll);
	printf("isdndev.tflags       = %d\n", my_isdndev->tflags);
	printf("isdndev.global_flags = %d\n", my_isdndev->global_flags);
	if (my_isdndev->infochain) {
		printf("isdndev.infochain    = @%08lx:\n", (ulong) my_isdndev->infochain);
	} else
		printf("isdndev.infochain    = NULL\n");
	if (my_isdndev->info_waitq) {
		printf("isdndev.info_waitq   = @%08lx:\n", (ulong) my_isdndev->info_waitq);
	} else
		printf("isdndev.info_waitq   = NULL\n");
	printf("isdndev.chanmap      = %s\n",
	       dumpIntArray(my_isdndev->chanmap, ISDN_MAX_CHANNELS));
	printf("isdndev.drvmap       = %s\n",
	       dumpIntArray(my_isdndev->drvmap, ISDN_MAX_CHANNELS));
	printf("isdndev.usage        = %s\n",
	       dumpIntArray(my_isdndev->usage, ISDN_MAX_CHANNELS));
	printf("isdndev.num          = %s\n",
	     dumpStringArray(my_isdndev->num[0], ISDN_MAX_CHANNELS, 20));
	printf("isdndev.m_idx        = %s\n",
	       dumpIntArray(my_isdndev->m_idx, ISDN_MAX_CHANNELS));
	dumpModem(my_isdndev->mdm);
	for (i = 0; i < ISDN_MAX_DRIVERS; i++)
		if (my_isdndev->drv[i]) {
			printf("isdndev.drv[%02d]      = @%08lx:\n", i, (ulong) my_isdndev->drv[i]);
			dumpDriver((ulong) (my_isdndev->drv[i]));
		}
	if (my_isdndev->netdev) {
		printf("isdndev.netdev       = @%08lx:\n", (ulong) my_isdndev->netdev);
		dumpNetDev((ulong) my_isdndev->netdev);
	} else
		printf("isdndev.netdev       = NULL\n");
	close(mem_fd);
}
