Initial release

This commit is contained in:
Werner Cornelius 2000-02-10 19:47:50 +00:00
parent c190083506
commit bd47cdf255
14 changed files with 3771 additions and 0 deletions

View File

@ -0,0 +1,24 @@
SUB_DIRS :=
MOD_SUB_DIRS :=
ALL_SUB_DIRS :=
L_OBJS :=
LX_OBJS :=
M_OBJS :=
MX_OBJS :=
O_OBJS :=
OX_OBJS :=
L_TARGET :=
O_TARGET :=
ifeq ($(CONFIG_PROC_FS),y)
ifeq ($(CONFIG_HYSDN),y)
M_OBJS += hysdn.o
O_TARGET += hysdn.o
O_OBJS += hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o hysdn_sched.o hysdn_net.o
OX_OBJS += hysdn_init.o
endif
endif
include $(TOPDIR)/Rules.make

View File

@ -0,0 +1,464 @@
/* $Id$
* Linux driver for HYSDN cards, specific routines for ergo type boards.
*
* As all Linux supported cards Champ2, Ergo and Metro2/4 use the same
* DPRAM interface and layout with only minor differences all related
* stuff is done here, not in separate modules.
*
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* 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$
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <asm/io.h>
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include "hysdn_defs.h"
#include "boardergo.h"
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
/***************************************************/
/* The cards interrupt handler. Called from system */
/***************************************************/
static void
ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
hysdn_card *card = dev_id; /* parameter from irq */
tErgDpram *dpr;
ulong flags;
uchar volatile b;
if (!card)
return; /* error -> spurious interrupt */
if (!card->irq_enabled)
return; /* other device interrupting or irq switched off */
save_flags(flags);
cli(); /* no further irqs allowed */
if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) {
restore_flags(flags); /* restore old state */
return; /* no interrupt requested by E1 */
}
/* clear any pending ints on the board */
dpr = card->dpram;
b = dpr->ToPcInt; /* clear for ergo */
b |= dpr->ToPcIntMetro; /* same for metro */
b |= dpr->ToHyInt; /* and for champ */
/* start kernel task immediately after leaving all interrupts */
if (!card->hw_lock) {
queue_task(&card->irq_queue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
restore_flags(flags);
} /* ergo_interrupt */
/******************************************************************************/
/* ergo_irq_bh is the function called by the immediate kernel task list after */
/* being activated with queue_task and no interrupts active. This task is the */
/* only one handling data transfer from or to the card after booting. The task */
/* may be queued from everywhere (interrupts included). */
/******************************************************************************/
static void
ergo_irq_bh(hysdn_card * card)
{
tErgDpram *dpr;
int again;
ulong flags;
if (card->state != CARD_STATE_RUN)
return; /* invalid call */
dpr = card->dpram; /* point to DPRAM */
save_flags(flags);
cli();
if (card->hw_lock) {
restore_flags(flags); /* hardware currently unavailable */
return;
}
card->hw_lock = 1; /* we now lock the hardware */
do {
sti(); /* reenable other ints */
again = 0; /* assume loop not to be repeated */
if (!dpr->ToHyFlag) {
/* we are able to send a buffer */
if (hysdn_sched_tx(card, dpr->ToHyBuf, &dpr->ToHySize, &dpr->ToHyChannel,
ERG_TO_HY_BUF_SIZE)) {
dpr->ToHyFlag = 1; /* enable tx */
again = 1; /* restart loop */
}
} /* we are able to send a buffer */
if (dpr->ToPcFlag) {
/* a message has arrived for us, handle it */
if (hysdn_sched_rx(card, dpr->ToPcBuf, dpr->ToPcSize, dpr->ToPcChannel)) {
dpr->ToPcFlag = 0; /* we worked the data */
again = 1; /* restart loop */
}
} /* a message has arrived for us */
cli(); /* no further ints */
if (again) {
dpr->ToHyInt = 1;
dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
} else
card->hw_lock = 0; /* free hardware again */
} while (again); /* until nothing more to do */
restore_flags(flags);
} /* ergo_irq_bh */
/*********************************************************/
/* stop the card (hardware reset) and disable interrupts */
/*********************************************************/
static void
ergo_stopcard(hysdn_card * card)
{
ulong flags;
uchar val;
hysdn_net_release(card); /* first release the net device if existing */
save_flags(flags);
cli();
val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */
val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */
byteout(card->iobase + PCI9050_INTR_REG, val);
card->irq_enabled = 0;
byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RESET); /* reset E1 processor */
card->state = CARD_STATE_UNUSED;
card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */
restore_flags(flags);
} /* ergo_stopcard */
/**************************************************************************/
/* enable or disable the cards error log. The event is queued if possible */
/**************************************************************************/
static void
ergo_set_errlog_state(hysdn_card * card, int on)
{
ulong flags;
if (card->state != CARD_STATE_RUN) {
card->err_log_state = ERRLOG_STATE_OFF; /* must be off */
return;
}
save_flags(flags);
cli();
if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) ||
((card->err_log_state == ERRLOG_STATE_ON) && on)) {
restore_flags(flags);
return; /* nothing to do */
}
if (on)
card->err_log_state = ERRLOG_STATE_START; /* request start */
else
card->err_log_state = ERRLOG_STATE_STOP; /* request stop */
restore_flags(flags);
queue_task(&card->irq_queue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
} /* ergo_set_errlog_state */
/******************************************/
/* test the cards RAM and return 0 if ok. */
/******************************************/
static const char TestText[36] = "This Message is filler, why read it";
static int
ergo_testram(hysdn_card * card)
{
tErgDpram *dpr = card->dpram;
memset(dpr->TrapTable, 0, sizeof(dpr->TrapTable)); /* clear all Traps */
dpr->ToHyInt = 1; /* E1 INTR state forced */
memcpy(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText,
sizeof(TestText));
if (memcmp(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText,
sizeof(TestText)))
return (-1);
memcpy(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText,
sizeof(TestText));
if (memcmp(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText,
sizeof(TestText)))
return (-1);
return (0);
} /* ergo_testram */
/*****************************************************************************/
/* this function is intended to write stage 1 boot image to the cards buffer */
/* this is done in two steps. First the 1024 hi-words are written (offs=0), */
/* then the 1024 lo-bytes are written. The remaining DPRAM is cleared, the */
/* PCI-write-buffers flushed and the card is taken out of reset. */
/* The function then waits for a reaction of the E1 processor or a timeout. */
/* Negative return values are interpreted as errors. */
/*****************************************************************************/
static int
ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs)
{
uchar *dst;
tErgDpram *dpram;
int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs);
dst = card->dpram; /* pointer to start of DPRAM */
dst += (offs + ERG_DPRAM_FILL_SIZE); /* offset in the DPRAM */
while (cnt--) {
*dst++ = *(buf + 1); /* high byte */
*dst++ = *buf; /* low byte */
dst += 2; /* point to next longword */
buf += 2; /* buffer only filled with words */
}
/* if low words (offs = 2) have been written, clear the rest of the DPRAM, */
/* flush the PCI-write-buffer and take the E1 out of reset */
if (offs) {
memset(card->dpram, 0, ERG_DPRAM_FILL_SIZE); /* fill the DPRAM still not cleared */
dpram = card->dpram; /* get pointer to dpram structure */
dpram->ToHyNoDpramErrLog = 0xFF; /* write a dpram register */
while (!dpram->ToHyNoDpramErrLog); /* reread volatile register to flush PCI */
byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RUN); /* start E1 processor */
/* the interrupts are still masked */
sti();
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
if (((tDpramBootSpooler *) card->dpram)->Len != DPRAM_SPOOLER_DATA_SIZE) {
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: write bootldr no answer");
return (-ERR_BOOTIMG_FAIL);
}
} /* start_boot_img */
return (0); /* successfull */
} /* ergo_writebootimg */
/********************************************************************************/
/* ergo_writebootseq writes the buffer containing len bytes to the E1 processor */
/* using the boot spool mechanism. If everything works fine 0 is returned. In */
/* case of errors a negative error value is returned. */
/********************************************************************************/
static int
ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len)
{
tDpramBootSpooler *sp = (tDpramBootSpooler *) card->dpram;
uchar *dst;
uchar buflen;
int nr_write;
uchar tmp_rdptr;
uchar wr_mirror;
int i;
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: write boot seq len=%d ", len);
dst = sp->Data; /* point to data in spool structure */
buflen = sp->Len; /* maximum len of spooled data */
wr_mirror = sp->WrPtr; /* only once read */
sti();
/* try until all bytes written or error */
i = 0x1000; /* timeout value */
while (len) {
/* first determine the number of bytes that may be buffered */
do {
tmp_rdptr = sp->RdPtr; /* first read the pointer */
i--; /* decrement timeout */
} while (i && (tmp_rdptr != sp->RdPtr)); /* wait for stable pointer */
if (!i) {
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: write boot seq timeout");
return (-ERR_BOOTSEQ_FAIL); /* value not stable -> timeout */
}
if ((nr_write = tmp_rdptr - wr_mirror - 1) < 0)
nr_write += buflen; /* now we got number of free bytes - 1 in buffer */
if (!nr_write)
continue; /* no free bytes in buffer */
if (nr_write > len)
nr_write = len; /* limit if last few bytes */
i = 0x1000; /* reset timeout value */
/* now we know how much bytes we may put in the puffer */
len -= nr_write; /* we savely could adjust len before output */
while (nr_write--) {
*(dst + wr_mirror) = *buf++; /* output one byte */
if (++wr_mirror >= buflen)
wr_mirror = 0;
sp->WrPtr = wr_mirror; /* announce the next byte to E1 */
} /* while (nr_write) */
} /* while (len) */
return (0);
} /* ergo_writebootseq */
/***********************************************************************************/
/* ergo_waitpofready waits for a maximum of 10 seconds for the completition of the */
/* boot process. If the process has been successfull 0 is returned otherwise a */
/* negative error code is returned. */
/***********************************************************************************/
static int
ergo_waitpofready(struct HYSDN_CARD *card)
{
tErgDpram *dpr = card->dpram; /* pointer to DPRAM structure */
int timecnt = 10000 / 50; /* timeout is 10 secs max. */
ulong flags;
int msg_size;
int i;
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: waiting for pof ready");
while (timecnt--) {
/* wait until timeout */
if (dpr->ToPcFlag) {
/* data has arrived */
if ((dpr->ToPcChannel != CHAN_SYSTEM) ||
(dpr->ToPcSize < MIN_RDY_MSG_SIZE) ||
(dpr->ToPcSize > MAX_RDY_MSG_SIZE) ||
((*(ulong *) dpr->ToPcBuf) != RDY_MAGIC))
break; /* an error occured */
/* Check for additional data delivered during SysReady */
msg_size = dpr->ToPcSize - RDY_MAGIC_SIZE;
if (msg_size > 0)
if (EvalSysrTokData(card, dpr->ToPcBuf + RDY_MAGIC_SIZE, msg_size))
break;
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "ERGO: pof boot success");
save_flags(flags);
cli();
card->state = CARD_STATE_RUN; /* now card is running */
/* enable the cards interrupt */
byteout(card->iobase + PCI9050_INTR_REG,
bytein(card->iobase + PCI9050_INTR_REG) |
(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1));
card->irq_enabled = 1; /* we are ready to receive interrupts */
dpr->ToPcFlag = 0; /* reset data indicator */
dpr->ToHyInt = 1;
dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
restore_flags(flags);
if ((i = hysdn_net_create(card))) {
ergo_stopcard(card);
card->state = CARD_STATE_BOOTERR;
return (i);
}
return (0); /* success */
} /* data has arrived */
sti();
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((50 * HZ) / 1000); /* Timeout 50ms */
} /* wait until timeout */
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: pof boot ready timeout");
return (-ERR_POF_TIMEOUT);
} /* ergo_waitpofready */
/************************************************************************************/
/* release the cards hardware. Before releasing do a interrupt disable and hardware */
/* reset. Also unmap dpram. */
/* Use only during module release. */
/************************************************************************************/
static void
ergo_releasehardware(hysdn_card * card)
{
ergo_stopcard(card); /* first stop the card if not already done */
free_irq(card->irq, card); /* release interrupt */
release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */
release_region(card->iobase + PCI9050_USER_IO, 1);
vfree(card->dpram);
card->dpram = NULL; /* release shared mem */
} /* ergo_releasehardware */
/*********************************************************************************/
/* acquire the needed hardware ports and map dpram. If an error occurs a nonzero */
/* value is returned. */
/* Use only during module init. */
/*********************************************************************************/
int
ergo_inithardware(hysdn_card * card)
{
if (check_region(card->iobase + PCI9050_INTR_REG, 1) ||
check_region(card->iobase + PCI9050_USER_IO, 1))
return (-1); /* ports already in use */
card->memend = card->membase + ERG_DPRAM_PAGE_SIZE - 1;
if (!(card->dpram = ioremap(card->membase, ERG_DPRAM_PAGE_SIZE)))
return (-1);
request_region(card->iobase + PCI9050_INTR_REG, 1, "HYSDN");
request_region(card->iobase + PCI9050_USER_IO, 1, "HYSDN");
ergo_stopcard(card); /* disable interrupts */
if (request_irq(card->irq, ergo_interrupt, SA_SHIRQ, "HYSDN", card)) {
ergo_releasehardware(card); /* return the aquired hardware */
return (-1);
}
/* success, now setup the function pointers */
card->stopcard = ergo_stopcard;
card->releasehardware = ergo_releasehardware;
card->testram = ergo_testram;
card->writebootimg = ergo_writebootimg;
card->writebootseq = ergo_writebootseq;
card->waitpofready = ergo_waitpofready;
card->set_errlog_state = ergo_set_errlog_state;
card->irq_queue.next = 0;
card->irq_queue.sync = 0;
card->irq_queue.data = card; /* init task queue for interrupt */
card->irq_queue.routine = (void *) (void *) ergo_irq_bh;
return (0);
} /* ergo_inithardware */

View File

@ -0,0 +1,114 @@
/* $Id$
* Linux driver for HYSDN cards, definitions for ergo type boards (buffers..).
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* 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$
*
*/
#include <linux/isdn_compat.h>
/************************************************/
/* defines for the dual port memory of the card */
/************************************************/
#define ERG_DPRAM_PAGE_SIZE 0x2000 /* DPRAM occupies a 8K page */
#define BOOT_IMG_SIZE 4096
#define ERG_DPRAM_FILL_SIZE (ERG_DPRAM_PAGE_SIZE - BOOT_IMG_SIZE)
#define ERG_TO_HY_BUF_SIZE 0x0E00 /* 3072 bytes buffer size to card */
#define ERG_TO_PC_BUF_SIZE 0x0E00 /* 3072 bytes to PC, too */
/* following DPRAM layout copied from OS2-driver boarderg.h */
typedef struct ErgDpram_tag {
/*0000 */ uchar ToHyBuf[ERG_TO_HY_BUF_SIZE];
/*0E00 */ uchar ToPcBuf[ERG_TO_PC_BUF_SIZE];
/*1C00 */ uchar bSoftUart[SIZE_RSV_SOFT_UART];
/* size 0x1B0 */
/*1DB0 *//* tErrLogEntry */ uchar volatile ErrLogMsg[64];
/* size 64 bytes */
/*1DB0 ulong ulErrType; */
/*1DB4 ulong ulErrSubtype; */
/*1DB8 ulong ucTextSize; */
/*1DB9 ulong ucText[ERRLOG_TEXT_SIZE]; *//* ASCIIZ of len ucTextSize-1 */
/*1DF0 */
/*1DF0 */ word volatile ToHyChannel;
/*1DF2 */ word volatile ToHySize;
/*1DF4 */ uchar volatile ToHyFlag;
/* !=0: msg for Hy waiting */
/*1DF5 */ uchar volatile ToPcFlag;
/* !=0: msg for PC waiting */
/*1DF6 */ word volatile ToPcChannel;
/*1DF8 */ word volatile ToPcSize;
/*1DFA */ uchar bRes1DBA[0x1E00 - 0x1DFA];
/* 6 bytes */
/*1E00 */ uchar bRestOfEntryTbl[0x1F00 - 0x1E00];
/*1F00 */ ulong TrapTable[62];
/*1FF8 */ uchar bRes1FF8[0x1FFB - 0x1FF8];
/* low part of reset vetor */
/*1FFB */ uchar ToPcIntMetro;
/* notes:
* - metro has 32-bit boot ram - accessing
* ToPcInt and ToHyInt would be the same;
* so we moved ToPcInt to 1FFB.
* Because on the PC side both vars are
* readonly (reseting on int from E1 to PC),
* we can read both vars on both cards
* without destroying anything.
* - 1FFB is the high byte of the reset vector,
* so E1 side should NOT change this byte
* when writing!
*/
/*1FFC */ uchar volatile ToHyNoDpramErrLog;
/* note: ToHyNoDpramErrLog is used to inform
* boot loader, not to use DPRAM based
* ErrLog; when DOS driver is rewritten
* this becomes obsolete
*/
/*1FFD */ uchar bRes1FFD;
/*1FFE */ uchar ToPcInt;
/* E1_intclear; on CHAMP2: E1_intset */
/*1FFF */ uchar ToHyInt;
/* E1_intset; on CHAMP2: E1_intclear */
} tErgDpram;
/**********************************************/
/* PCI9050 controller local register offsets: */
/* copied from boarderg.c */
/**********************************************/
#define PCI9050_INTR_REG 0x4C /* Interrupt register */
#define PCI9050_USER_IO 0x51 /* User I/O register */
/* bitmask for PCI9050_INTR_REG: */
#define PCI9050_INTR_REG_EN1 0x01 /* 1= enable (def.), 0= disable */
#define PCI9050_INTR_REG_POL1 0x02 /* 1= active high (def.), 0= active low */
#define PCI9050_INTR_REG_STAT1 0x04 /* 1= intr. active, 0= intr. not active (def.) */
#define PCI9050_INTR_REG_ENPCI 0x40 /* 1= PCI interrupts enable (def.) */
/* bitmask for PCI9050_USER_IO: */
#define PCI9050_USER_IO_EN3 0x02 /* 1= disable , 0= enable (def.) */
#define PCI9050_USER_IO_DIR3 0x04 /* 1= output (def.), 0= input */
#define PCI9050_USER_IO_DAT3 0x08 /* 1= high (def.) , 0= low */
#define PCI9050_E1_RESET ( PCI9050_USER_IO_DIR3) /* 0x04 */
#define PCI9050_E1_RUN (PCI9050_USER_IO_DAT3|PCI9050_USER_IO_DIR3) /* 0x0C */

View File

@ -0,0 +1,417 @@
/* $Id$
* Linux driver for HYSDN cards, specific routines for booting and pof handling.
*
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* 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$
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/malloc.h>
#include <asm/uaccess.h>
#include "hysdn_defs.h"
#include "hysdn_pof.h"
/********************************/
/* defines for pof read handler */
/********************************/
#define POF_READ_FILE_HEAD 0
#define POF_READ_TAG_HEAD 1
#define POF_READ_TAG_DATA 2
/************************************************************/
/* definition of boot specific data area. This data is only */
/* needed during boot and so allocated dynamically. */
/************************************************************/
struct boot_data {
word Cryptor; /* for use with Decrypt function */
word Nrecs; /* records remaining in file */
uchar pof_state; /* actual state of read handler */
uchar is_crypted; /* card data is crypted */
int BufSize; /* actual number of bytes bufferd */
int last_error; /* last occured error */
word pof_recid; /* actual pof recid */
ulong pof_reclen; /* total length of pof record data */
ulong pof_recoffset; /* actual offset inside pof record */
union {
uchar BootBuf[BOOT_BUF_SIZE]; /* buffer as byte count */
tPofRecHdr PofRecHdr; /* header for actual record/chunk */
tPofFileHdr PofFileHdr; /* header from POF file */
tPofTimeStamp PofTime; /* time information */
} buf;
};
/*****************************************************/
/* start decryption of sucessive POF file chuncks. */
/* */
/* to be called at start of POF file reading, */
/* before starting any decryption on any POF record. */
/*****************************************************/
void
StartDecryption(struct boot_data *boot)
{
boot->Cryptor = CRYPT_STARTTERM;
} /* StartDecryption */
/***************************************************************/
/* decrypt complete BootBuf */
/* NOTE: decryption must be applied to all or none boot tags - */
/* to HI and LO boot loader and (all) seq tags, because */
/* global Cryptor is started for whole POF. */
/***************************************************************/
void
DecryptBuf(struct boot_data *boot, int cnt)
{
uchar *bufp = boot->buf.BootBuf;
while (cnt--) {
boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0);
*bufp++ ^= (uchar) boot->Cryptor;
}
} /* DecryptBuf */
/********************************************************************************/
/* pof_handle_data executes the required actions dependant on the active record */
/* id. If successfull 0 is returned, a negative value shows an error. */
/********************************************************************************/
static int
pof_handle_data(hysdn_card * card, int datlen)
{
struct boot_data *boot = card->boot; /* pointer to boot specific data */
long l;
uchar *imgp;
int img_len;
/* handle the different record types */
switch (boot->pof_recid) {
case TAG_TIMESTMP:
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText);
break;
case TAG_CBOOTDTA:
DecryptBuf(boot, datlen); /* we need to encrypt the buffer */
case TAG_BOOTDTA:
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
(boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA",
datlen, boot->pof_recoffset);
if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) {
boot->last_error = EPOF_BAD_IMG_SIZE; /* invalid length */
return (boot->last_error);
}
imgp = boot->buf.BootBuf; /* start of buffer */
img_len = datlen; /* maximum length to transfer */
l = POF_BOOT_LOADER_OFF_IN_PAGE -
(boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1));
if (l > 0) {
/* buffer needs to be truncated */
imgp += l; /* advance pointer */
img_len -= l; /* adjust len */
}
/* at this point no special handling for data wrapping over buffer */
/* is necessary, because the boot image always will be adjusted to */
/* match a page boundary inside the buffer. */
/* The buffer for the boot image on the card is filled in 2 cycles */
/* first the 1024 hi-words are put in the buffer, then the low 1024 */
/* word are handled in the same way with different offset. */
if (img_len > 0) {
/* data available for copy */
if ((boot->last_error =
card->writebootimg(card, imgp,
(boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0)
return (boot->last_error);
}
break; /* end of case boot image hi/lo */
case TAG_CABSDATA:
DecryptBuf(boot, datlen); /* we need to encrypt the buffer */
case TAG_ABSDATA:
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
(boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA",
datlen, boot->pof_recoffset);
if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0))
return (boot->last_error); /* error writing data */
if (boot->pof_recoffset + datlen >= boot->pof_reclen)
return (card->waitpofready(card)); /* data completely spooled, wait for ready */
break; /* end of case boot seq data */
default:
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid,
datlen, boot->pof_recoffset);
break; /* simply skip record */
} /* switch boot->pof_recid */
return (0);
} /* pof_handle_data */
/******************************************************************************/
/* pof_write_buffer is called when the buffer has been filled with the needed */
/* number of data bytes. The number delivered is additionally supplied for */
/* verification. The functions handles the data and returns the needed number */
/* of bytes for the next action. If the returned value is 0 or less an error */
/* occured and booting must be aborted. */
/******************************************************************************/
int
pof_write_buffer(hysdn_card * card, int datlen)
{
struct boot_data *boot = card->boot; /* pointer to boot specific data */
if (!boot)
return (-EFAULT); /* invalid call */
if (boot->last_error < 0)
return (boot->last_error); /* repeated error */
if (card->debug_flags & LOG_POF_WRITE)
hysdn_addlog(card, "POF write: got %d bytes ", datlen);
switch (boot->pof_state) {
case POF_READ_FILE_HEAD:
if (card->debug_flags & LOG_POF_WRITE)
hysdn_addlog(card, "POF write: checking file header");
if (datlen != sizeof(tPofFileHdr)) {
boot->last_error = -EPOF_INTERNAL;
break;
}
if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) {
boot->last_error = -EPOF_BAD_MAGIC;
break;
}
/* Setup the new state and vars */
boot->Nrecs = (word) (boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */
boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
boot->last_error = sizeof(tPofRecHdr); /* new length */
break;
case POF_READ_TAG_HEAD:
if (card->debug_flags & LOG_POF_WRITE)
hysdn_addlog(card, "POF write: checking tag header");
if (datlen != sizeof(tPofRecHdr)) {
boot->last_error = -EPOF_INTERNAL;
break;
}
boot->pof_recid = boot->buf.PofRecHdr.PofRecId; /* actual pof recid */
boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen; /* total length */
boot->pof_recoffset = 0; /* no starting offset */
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ",
boot->pof_recid, boot->pof_reclen);
boot->pof_state = POF_READ_TAG_DATA; /* now start with tag data */
if (boot->pof_reclen < BOOT_BUF_SIZE)
boot->last_error = boot->pof_reclen; /* limit size */
else
boot->last_error = BOOT_BUF_SIZE; /* maximum */
if (!boot->last_error) { /* no data inside record */
boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
boot->last_error = sizeof(tPofRecHdr); /* new length */
}
break;
case POF_READ_TAG_DATA:
if (card->debug_flags & LOG_POF_WRITE)
hysdn_addlog(card, "POF write: getting tag data");
if (datlen != boot->last_error) {
boot->last_error = -EPOF_INTERNAL;
break;
}
if ((boot->last_error = pof_handle_data(card, datlen)) < 0)
return (boot->last_error); /* an error occured */
boot->pof_recoffset += datlen;
if (boot->pof_recoffset >= boot->pof_reclen) {
boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
boot->last_error = sizeof(tPofRecHdr); /* new length */
} else {
if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE)
boot->last_error = boot->pof_reclen - boot->pof_recoffset; /* limit size */
else
boot->last_error = BOOT_BUF_SIZE; /* maximum */
}
break;
default:
boot->last_error = -EPOF_INTERNAL; /* unknown state */
break;
} /* switch (boot->pof_state) */
return (boot->last_error);
} /* pof_write_buffer */
/*******************************************************************************/
/* pof_write_open is called when an open for boot on the cardlog device occurs. */
/* The function returns the needed number of bytes for the next operation. If */
/* the returned number is less or equal 0 an error specified by this code */
/* occurred. Additionally the pointer to the buffer data area is set on success */
/*******************************************************************************/
int
pof_write_open(hysdn_card * card, uchar ** bufp)
{
struct boot_data *boot; /* pointer to boot specific data */
if (card->boot) {
if (card->debug_flags & LOG_POF_OPEN)
hysdn_addlog(card, "POF open: already opened for boot");
return (-ERR_ALREADY_BOOT); /* boot already active */
}
/* error no mem available */
if (!(boot = kmalloc(sizeof(struct boot_data), GFP_KERNEL))) {
if (card->debug_flags & LOG_MEM_ERR)
hysdn_addlog(card, "POF open: unable to allocate mem");
return (-EFAULT);
}
card->boot = boot;
card->state = CARD_STATE_BOOTING;
memset(boot, 0, sizeof(struct boot_data));
card->stopcard(card); /* first stop the card */
if (card->testram(card)) {
if (card->debug_flags & LOG_POF_OPEN)
hysdn_addlog(card, "POF open: DPRAM test failure");
boot->last_error = -ERR_BOARD_DPRAM;
card->state = CARD_STATE_BOOTERR; /* show boot error */
return (boot->last_error);
}
boot->BufSize = 0; /* Buffer is empty */
boot->pof_state = POF_READ_FILE_HEAD; /* read file header */
StartDecryption(boot); /* if POF File should be encrypted */
if (card->debug_flags & LOG_POF_OPEN)
hysdn_addlog(card, "POF open: success");
*bufp = boot->buf.BootBuf; /* point to buffer */
return (sizeof(tPofFileHdr));
} /* pof_write_open */
/********************************************************************************/
/* pof_write_close is called when an close of boot on the cardlog device occurs. */
/* The return value must be 0 if everything has happened as desired. */
/********************************************************************************/
int
pof_write_close(hysdn_card * card)
{
struct boot_data *boot = card->boot; /* pointer to boot specific data */
if (!boot)
return (-EFAULT); /* invalid call */
card->boot = NULL; /* no boot active */
kfree(boot);
if (card->state == CARD_STATE_RUN)
card->set_errlog_state(card, 1); /* activate error log */
if (card->debug_flags & LOG_POF_OPEN)
hysdn_addlog(card, "POF close: success");
return (0);
} /* pof_write_close */
/*********************************************************************************/
/* EvalSysrTokData checks additional records delivered with the Sysready Message */
/* when POF has been booted. A return value of 0 is used if no error occured. */
/*********************************************************************************/
int
EvalSysrTokData(hysdn_card * card, uchar * cp, int len)
{
u_char *p;
u_char crc;
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "SysReady Token data length %d", len);
if (len < 2) {
hysdn_addlog(card, "SysReady Token Data to short");
return (1);
}
for (p = cp, crc = 0; p < (cp + len - 2); p++)
if ((crc & 0x80))
crc = (((u_char) (crc << 1)) + 1) + *p;
else
crc = ((u_char) (crc << 1)) + *p;
crc = ~crc;
if (crc != *(cp + len - 1)) {
hysdn_addlog(card, "SysReady Token Data invalid CRC");
return (1);
}
len--; /* dont check CRC byte */
while (len > 0) {
if (*cp == SYSR_TOK_END)
return (0); /* End of Token stream */
if (len < (*(cp + 1) + 2)) {
hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1));
return (1);
}
switch (*cp) {
case SYSR_TOK_B_CHAN: /* 1 */
if (*(cp + 1) != 1)
return (1); /* length invalid */
card->bchans = *(cp + 2);
break;
case SYSR_TOK_FAX_CHAN: /* 2 */
if (*(cp + 1) != 1)
return (1); /* length invalid */
card->faxchans = *(cp + 2);
break;
case SYSR_TOK_MAC_ADDR: /* 3 */
if (*(cp + 1) != 6)
return (1); /* length invalid */
memcpy(card->mac_addr, cp + 2, 6);
break;
default:
hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1));
break;
}
len -= (*(cp + 1) + 2); /* adjust len */
cp += (*(cp + 1) + 2); /* and pointer */
}
hysdn_addlog(card, "no end token found");
return (1);
} /* EvalSysrTokData */

View File

@ -0,0 +1,226 @@
/* $Id$
* Linux driver for HYSDN cards, global definitions and exported vars and functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* 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$
*
*/
#include <linux/hysdn_if.h>
#include <linux/interrupt.h>
#include <linux/tqueue.h>
#include <linux/skbuff.h>
#include <linux/isdn_compat.h>
/****************************/
/* storage type definitions */
/****************************/
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define word unsigned short
#include "ince1pc.h"
/************************************************/
/* constants and bits for debugging/log outputs */
/************************************************/
#define LOG_MAX_LINELEN 120
#define DEB_OUT_SYSLOG 0x80000000 /* output to syslog instead of proc fs */
#define LOG_MEM_ERR 0x00000001 /* log memory errors like kmalloc failure */
#define LOG_POF_OPEN 0x00000010 /* log pof open and close activities */
#define LOG_POF_RECORD 0x00000020 /* log pof record parser */
#define LOG_POF_WRITE 0x00000040 /* log detailed pof write operation */
#define LOG_POF_CARD 0x00000080 /* log pof related card functions */
#define LOG_CNF_LINE 0x00000100 /* all conf lines are put to procfs */
#define LOG_CNF_DATA 0x00000200 /* non comment conf lines are shown with channel */
#define LOG_CNF_MISC 0x00000400 /* additional conf line debug outputs */
#define LOG_SCHED_ASYN 0x00001000 /* debug schedulers async tx routines */
#define LOG_PROC_OPEN 0x00100000 /* open and close from procfs are logged */
#define LOG_PROC_ALL 0x00200000 /* all actions from procfs are logged */
#define LOG_NET_INIT 0x00010000 /* network init and deinit logging */
#define DEF_DEB_FLAGS 0x7fff000f /* everything is logged to procfs */
/**********************************/
/* proc filesystem name constants */
/**********************************/
#define PROC_SUBDIR_NAME "hysdn"
#define PROC_CONF_BASENAME "cardconf"
#define PROC_LOG_BASENAME "cardlog"
/************************/
/* PCI constant defines */
/************************/
#define PCI_VENDOR_ID_HYPERCOPE 0x1365
#define PCI_DEVICE_ID_PLX 0x9050 /* all DPRAM cards use the same id */
/*****************************/
/* sub ids determining cards */
/*****************************/
#define PCI_SUB_ID_OLD_ERGO 0x0104
#define PCI_SUB_ID_ERGO 0x0106
#define PCI_SUB_ID_METRO 0x0107
#define PCI_SUB_ID_CHAMP2 0x0108
#define PCI_SUB_ID_PLEXUS 0x0109
/***********************************/
/* PCI 32 bit parms for IO and MEM */
/***********************************/
#define PCI_REG_PLX_MEM_BASE 0
#define PCI_REG_PLX_IO_BASE 1
#define PCI_REG_MEMORY_BASE 3
/**************/
/* card types */
/**************/
#define BD_NONE 0U
#define BD_PERFORMANCE 1U
#define BD_VALUE 2U
#define BD_PCCARD 3U
#define BD_ERGO 4U
#define BD_METRO 5U
#define BD_CHAMP2 6U
#define BD_PLEXUS 7U
/******************************************************/
/* defined states for cards shown by reading cardconf */
/******************************************************/
#define CARD_STATE_UNUSED 0 /* never been used or booted */
#define CARD_STATE_BOOTING 1 /* booting is in progress */
#define CARD_STATE_BOOTERR 2 /* a previous boot was aborted */
#define CARD_STATE_RUN 3 /* card is active */
/*******************************/
/* defines for error_log_state */
/*******************************/
#define ERRLOG_STATE_OFF 0 /* error log is switched off, nothing to do */
#define ERRLOG_STATE_ON 1 /* error log is switched on, wait for data */
#define ERRLOG_STATE_START 2 /* start error logging */
#define ERRLOG_STATE_STOP 3 /* stop error logging */
/*******************************/
/* data structure for one card */
/*******************************/
typedef struct HYSDN_CARD {
/* general variables for the cards */
int myid; /* own driver card id */
uchar bus; /* pci bus the card is connected to */
uchar devfn; /* slot+function bit encoded */
word subsysid; /* PCI subsystem id */
uchar brdtype; /* type of card */
uint bchans; /* number of available B-channels */
uint faxchans; /* number of available fax-channels */
uchar mac_addr[6]; /* MAC Address read from card */
uint irq; /* interrupt number */
uint iobase; /* IO-port base address */
ulong plxbase; /* PLX memory base */
ulong membase; /* DPRAM memory base */
ulong memend; /* DPRAM memory end */
void *dpram; /* mapped dpram */
int state; /* actual state of card -> CARD_STATE_** */
struct HYSDN_CARD *next; /* pointer to next card */
/* data areas for the /proc file system */
void *proclog; /* pointer to proclog filesystem specific data */
void *procconf; /* pointer to procconf filesystem specific data */
/* debugging and logging */
uchar err_log_state; /* actual error log state of the card */
ulong debug_flags; /* tells what should be debugged and where */
void (*set_errlog_state) (struct HYSDN_CARD *, int);
/* interrupt handler + interrupt synchronisation */
struct tq_struct irq_queue; /* interrupt task queue */
uchar volatile irq_enabled; /* interrupt enabled if != 0 */
uchar volatile hw_lock; /* hardware is currently locked -> no access */
/* boot process */
void *boot; /* pointer to boot private data */
int (*writebootimg) (struct HYSDN_CARD *, uchar *, ulong);
int (*writebootseq) (struct HYSDN_CARD *, uchar *, int);
int (*waitpofready) (struct HYSDN_CARD *);
int (*testram) (struct HYSDN_CARD *);
/* scheduler for data transfer (only async parts) */
uchar async_data[256]; /* async data to be sent (normally for config) */
word volatile async_len; /* length of data to sent */
word volatile async_channel; /* channel number for async transfer */
int volatile async_busy; /* flag != 0 sending in progress */
int volatile net_tx_busy; /* a network packet tx is in progress */
/* network interface */
void *netif; /* pointer to network structure */
/* init and deinit stopcard for booting, too */
void (*stopcard) (struct HYSDN_CARD *);
void (*releasehardware) (struct HYSDN_CARD *);
} hysdn_card;
/*****************/
/* exported vars */
/*****************/
extern int cardmax; /* number of found cards */
extern hysdn_card *card_root; /* pointer to first card */
/*************************/
/* im/exported functions */
/*************************/
extern int printk(const char *fmt,...);
extern char *hysdn_getrev(const char *);
/* hysdn_procconf.c */
extern int hysdn_procconf_init(void); /* init proc config filesys */
extern void hysdn_procconf_release(void); /* deinit proc config filesys */
/* hysdn_proclog.c */
extern int hysdn_proclog_init(hysdn_card *); /* init proc log entry */
extern void hysdn_proclog_release(hysdn_card *); /* deinit proc log entry */
extern void put_log_buffer(hysdn_card *, char *); /* output log data */
extern void hysdn_addlog(hysdn_card *, char *,...); /* output data to log */
extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int); /* output card log */
/* boardergo.c */
extern int ergo_inithardware(hysdn_card * card); /* get hardware -> module init */
/* hysdn_boot.c */
extern int pof_write_close(hysdn_card *); /* close proc file after writing pof */
extern int pof_write_open(hysdn_card *, uchar **); /* open proc file for writing pof */
extern int pof_write_buffer(hysdn_card *, int); /* write boot data to card */
extern int EvalSysrTokData(hysdn_card *, uchar *, int); /* Check Sysready Token Data */
/* hysdn_sched.c */
extern int hysdn_sched_tx(hysdn_card *, uchar *, word volatile *, word volatile *,
word);
extern int hysdn_sched_rx(hysdn_card *, uchar *, word, word);
extern int hysdn_tx_cfgline(hysdn_card *, uchar *, word); /* send one cfg line */
/* hysdn_net.c */
extern char *hysdn_net_revision;
extern int hysdn_net_create(hysdn_card *); /* create a new net device */
extern int hysdn_net_release(hysdn_card *); /* delete the device */
extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */
extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */
extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */
extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */

View File

@ -0,0 +1,239 @@
/* $Id$
* Linux driver for HYSDN cards, init functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* 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$
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <linux/malloc.h>
#include <linux/pci.h>
#include "hysdn_defs.h"
static char *hysdn_init_revision = "$Revision$";
int cardmax; /* number of found cards */
hysdn_card *card_root = NULL; /* pointer to first card */
/**********************************************/
/* table assigning PCI-sub ids to board types */
/* the last entry contains all 0 */
/**********************************************/
static struct {
word subid; /* PCI sub id */
uchar cardtyp; /* card type assigned */
} pci_subid_map[] = {
{
PCI_SUB_ID_METRO, BD_METRO
},
{
PCI_SUB_ID_CHAMP2, BD_CHAMP2
},
{
PCI_SUB_ID_ERGO, BD_ERGO
},
{
PCI_SUB_ID_OLD_ERGO, BD_ERGO
},
{
0, 0
} /* terminating entry */
};
/*********************************************************************/
/* search_cards searches for available cards in the pci config data. */
/* If a card is found, the card structure is allocated and the cards */
/* ressources are reserved. cardmax is incremented. */
/*********************************************************************/
static void
search_cards(void)
{
struct pci_dev *akt_pcidev = NULL;
hysdn_card *card, *card_last;
uchar irq;
int i;
card_root = NULL;
card_last = NULL;
while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_PLX,
akt_pcidev)) != NULL) {
if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) {
printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
return;
}
memset(card, 0, sizeof(hysdn_card));
card->myid = cardmax; /* set own id */
card->bus = akt_pcidev->bus->number;
card->devfn = akt_pcidev->devfn; /* slot + function */
pcibios_read_config_word(card->bus, card->devfn, PCI_SUBSYSTEM_ID, &card->subsysid);
pcibios_read_config_byte(card->bus, card->devfn, PCI_INTERRUPT_LINE, &irq);
card->irq = irq;
card->iobase = get_pcibase(akt_pcidev, PCI_REG_PLX_IO_BASE) & PCI_BASE_ADDRESS_IO_MASK;
card->plxbase = get_pcibase(akt_pcidev, PCI_REG_PLX_MEM_BASE);
card->membase = get_pcibase(akt_pcidev, PCI_REG_MEMORY_BASE);
card->brdtype = BD_NONE; /* unknown */
card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
card->faxchans = 0; /* default no fax channels */
card->bchans = 2; /* and 2 b-channels */
for (i = 0; pci_subid_map[i].subid; i++)
if (pci_subid_map[i].subid == card->subsysid) {
card->brdtype = pci_subid_map[i].cardtyp;
break;
}
if (card->brdtype != BD_NONE) {
if (ergo_inithardware(card)) {
printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
kfree(card);
continue;
}
} else {
printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
kfree(card); /* release mem */
continue;
}
cardmax++;
card->next = NULL; /*end of chain */
if (card_last)
card_last->next = card; /* pointer to next card */
else
card_root = card;
card_last = card; /* new chain end */
} /* device found */
} /* search_cards */
/************************************************************************************/
/* free_resources frees the acquired PCI resources and returns the allocated memory */
/************************************************************************************/
static void
free_resources(void)
{
hysdn_card *card;
while (card_root) {
card = card_root;
if (card->releasehardware)
card->releasehardware(card); /* free all hardware resources */
card_root = card_root->next; /* remove card from chain */
kfree(card); /* return mem */
} /* while card_root */
} /* free_resources */
/**************************************************************************/
/* stop_cards disables (hardware resets) all cards and disables interrupt */
/**************************************************************************/
static void
stop_cards(void)
{
hysdn_card *card;
card = card_root; /* first in chain */
while (card) {
if (card->stopcard)
card->stopcard(card);
card = card->next; /* remove card from chain */
} /* while card */
} /* stop_cards */
/****************************************************************************/
/* The module startup and shutdown code. Only compiled when used as module. */
/* Using the driver as module is always advisable, because the booting */
/* image becomes smaller and the driver code is only loaded when needed. */
/* Additionally newer versions may be activated without rebooting. */
/****************************************************************************/
#ifdef CONFIG_MODULES
/******************************************************/
/* extract revision number from string for log output */
/******************************************************/
char *
hysdn_getrev(const char *revision)
{
char *rev;
char *p;
if ((p = strchr(revision, ':'))) {
rev = p + 2;
p = strchr(rev, '$');
*--p = 0;
} else
rev = "???";
return rev;
}
/****************************************************************************/
/* init_module is called once when the module is loaded to do all necessary */
/* things like autodetect... */
/* If the return value of this function is 0 the init has been successfull */
/* and the module is added to the list in /proc/modules, otherwise an error */
/* is assumed and the module will not be kept in memory. */
/****************************************************************************/
int
init_module(void)
{
char tmp[50];
strcpy(tmp, hysdn_init_revision);
printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
strcpy(tmp, hysdn_net_revision);
printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
if (!pci_present()) {
printk(KERN_ERR "HYSDN: no PCI bus present, module not loaded\n");
return (-1);
}
search_cards();
printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
if (hysdn_procconf_init()) {
free_resources(); /* proc file_sys not created */
return (-1);
}
return (0); /* no error */
} /* init_module */
/***********************************************************************/
/* cleanup_module is called when the module is released by the kernel. */
/* The routine is only called if init_module has been successfull and */
/* the module counter has a value of 0. Otherwise this function will */
/* not be called. This function must release all resources still allo- */
/* cated as after the return from this function the module code will */
/* be removed from memory. */
/***********************************************************************/
void
cleanup_module(void)
{
stop_cards();
hysdn_procconf_release();
free_resources();
printk(KERN_NOTICE "HYSDN: module unloaded\n");
} /* cleanup_module */
#endif /* CONFIG_MODULES */

View File

@ -0,0 +1,324 @@
/* $Id$
* Linux driver for HYSDN cards, net (ethernet type) handling routines.
*
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* This net module has been inspired by the skeleton driver from
* Donald Becker (becker@CESDIS.gsfc.nasa.gov)
*
* 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$
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/inetdevice.h>
#include "hysdn_defs.h"
/* store the actual version for log reporting */
char *hysdn_net_revision = "$Revision$";
/****************************************************************************/
/* structure containing the complete network data. The structure is aligned */
/* in a way that both, the device and statistics are kept inside it. */
/* for proper access, the device structure MUST be the first var/struct */
/* inside the definition. */
/****************************************************************************/
struct net_local {
struct device netdev; /* the network device */
struct net_device_stats stats;
/* additional vars may be added here */
char dev_name[9]; /* our own device name */
struct sk_buff *tx_skb; /* buffer for tx operation */
}; /* net_local */
/*****************************************************/
/* Get the current statistics for this card. */
/* This may be called with the card open or closed ! */
/*****************************************************/
static struct net_device_stats *
net_get_stats(struct device *dev)
{
return (&((struct net_local *) dev)->stats);
} /* net_device_stats */
/*********************************************************************/
/* Open/initialize the board. This is called (in the current kernel) */
/* sometime after booting when the 'ifconfig' program is run. */
/* This routine should set everything up anew at each open, even */
/* registers that "should" only need to be set once at boot, so that */
/* there is non-reboot way to recover if something goes wrong. */
/*********************************************************************/
static int
net_open(struct device *dev)
{
struct in_device *in_dev;
hysdn_card *card = dev->priv;
int i;
dev->tbusy = 0; /* non busy state */
dev->interrupt = 0;
if (!dev->start)
MOD_INC_USE_COUNT; /* increment only if device is down */
dev->start = 1; /* and started */
/* Fill in the MAC-level header (if not already set) */
if (!card->mac_addr[0]) {
for (i = 0; i < ETH_ALEN - sizeof(ulong); i++)
dev->dev_addr[i] = 0xfc;
if ((in_dev = dev->ip_ptr) != NULL) {
struct in_ifaddr *ifa = in_dev->ifa_list;
if (ifa != NULL)
memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ulong)), &ifa->ifa_local, sizeof(ulong));
}
} else
memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
return (0);
} /* net_open */
/*********************************************************************/
/* close/decativate the device. The device is not removed, but only */
/* deactivated. */
/*********************************************************************/
static int
net_close(struct device *dev)
{
dev->tbusy = 1; /* we are busy */
if (dev->start)
MOD_DEC_USE_COUNT; /* dec only if device has been active */
dev->start = 0; /* and not started */
return (0); /* success */
} /* net_close */
/************************************/
/* send a packet on this interface. */
/************************************/
static int
net_send_packet(struct sk_buff *skb, struct device *dev)
{
struct net_local *lp = (struct net_local *) dev;
if (dev->tbusy) {
/*
* If we get here, some higher level has decided we are broken.
* There should really be a "kick me" function call instead.
* As ISDN may have higher timeouts than real ethernet 10s timeout
*/
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < (10000 * HZ) / 1000)
return 1;
printk(KERN_WARNING "%s: transmit timed out. \n", dev->name);
dev->tbusy = 0;
dev->trans_start = jiffies;
}
/*
* Block a timer-based transmit from overlapping. This could better be
* done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
if (test_and_set_bit(0, (void *) &dev->tbusy) != 0)
printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
else {
lp->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
lp->tx_skb = skb; /* remember skb pointer */
queue_task(&((hysdn_card *) dev->priv)->irq_queue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
return (0); /* success */
} /* net_send_packet */
/***********************************************************************/
/* acknowlegde a packet send. The network layer will be informed about */
/* completion */
/***********************************************************************/
void
hysdn_tx_netack(hysdn_card * card)
{
struct net_local *lp = card->netif;
if (!lp)
return; /* non existing device */
if (lp->tx_skb)
dev_kfree_skb(lp->tx_skb); /* free tx pointer */
lp->tx_skb = NULL; /* reset pointer */
lp->stats.tx_packets++;
lp->netdev.tbusy = 0;
mark_bh(NET_BH); /* Inform upper layers. */
} /* hysdn_tx_netack */
/*****************************************************/
/* we got a packet from the network, go and queue it */
/*****************************************************/
void
hysdn_rx_netpkt(hysdn_card * card, uchar * buf, word len)
{
struct net_local *lp = card->netif;
struct sk_buff *skb;
if (!lp)
return; /* non existing device */
lp->stats.rx_bytes += len;
skb = dev_alloc_skb(len);
if (skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
lp->netdev.name);
lp->stats.rx_dropped++;
return;
}
skb->dev = &lp->netdev;
/* copy the data */
memcpy(skb_put(skb, len), buf, len);
/* determine the used protocol */
skb->protocol = eth_type_trans(skb, &lp->netdev);
netif_rx(skb);
lp->stats.rx_packets++; /* adjust packet count */
} /* hysdn_rx_netpkt */
/*****************************************************/
/* return the pointer to a network packet to be send */
/*****************************************************/
struct sk_buff *
hysdn_tx_netget(hysdn_card * card)
{
struct net_local *lp = card->netif;
if (!lp)
return (NULL); /* non existing device */
return (lp->tx_skb); /* return packet pointer */
} /* hysdn_tx_netget */
/*******************************************/
/* init function called by register device */
/*******************************************/
static int
net_init(struct device *dev)
{
/* setup the function table */
dev->open = net_open;
dev->stop = net_close;
dev->hard_start_xmit = net_send_packet;
dev->get_stats = net_get_stats;
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
return (0); /* success */
} /* net_init */
/*****************************************************************************/
/* hysdn_net_create creates a new net device for the given card. If a device */
/* already exists, it will be deleted and created a new one. The return value */
/* 0 announces success, else a negative error code will be returned. */
/*****************************************************************************/
int
hysdn_net_create(hysdn_card * card)
{
struct device *dev;
int i;
hysdn_net_release(card); /* release an existing net device */
if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
if (card->debug_flags & LOG_NET_INIT)
return (-ENOMEM);
}
memset(dev, 0, sizeof(struct net_local)); /* clean the structure */
/* initialise necessary or informing fields */
dev->base_addr = card->iobase; /* IO address */
dev->irq = card->irq; /* irq */
dev->init = net_init; /* the init function of the device */
dev->name = ((struct net_local *) dev)->dev_name; /* device name */
if ((i = register_netdev(dev))) {
printk(KERN_WARNING "HYSDN: unable to create network device\n");
kfree(dev);
return (i);
}
dev->priv = card; /* remember pointer to own data structure */
card->netif = dev; /* setup the local pointer */
if (card->debug_flags & LOG_NET_INIT)
hysdn_addlog(card, "network device created");
return (0); /* and return success */
} /* hysdn_net_create */
/***************************************************************************/
/* hysdn_net_release deletes the net device for the given card. The return */
/* value 0 announces success, else a negative error code will be returned. */
/***************************************************************************/
int
hysdn_net_release(hysdn_card * card)
{
struct device *dev = card->netif;
if (!dev)
return (0); /* non existing */
card->netif = NULL; /* clear out pointer */
dev->stop(dev); /* close the device */
unregister_netdev(dev); /* release the device */
kfree(dev); /* release the memory allocated */
if (card->debug_flags & LOG_NET_INIT)
hysdn_addlog(card, "network device deleted");
return (0); /* always successfull */
} /* hysdn_net_release */
/*****************************************************************************/
/* hysdn_net_getname returns a pointer to the name of the network interface. */
/* if the interface is not existing, a "-" is returned. */
/*****************************************************************************/
char *
hysdn_net_getname(hysdn_card * card)
{
struct device *dev = card->netif;
if (!dev)
return ("-"); /* non existing */
return (dev->name);
} /* hysdn_net_getname */

View File

@ -0,0 +1,91 @@
/* $Id$
* Linux driver for HYSDN cards, definitions used for handling pof-files.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* 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$
*
*/
/************************/
/* POF specific defines */
/************************/
#define BOOT_BUF_SIZE 0x1000 /* =4096, maybe moved to other h file */
#define CRYPT_FEEDTERM 0x8142
#define CRYPT_STARTTERM 0x81a5
/* max. timeout time in seconds
* from end of booting to POF is ready
*/
#define POF_READY_TIME_OUT_SEC 10
/**********************************/
/* defines for 1.stage boot image */
/**********************************/
/* the POF file record containing the boot loader image
* has 2 pages a 16KB:
* 1. page contains the high 16-bit part of the 32-bit E1 words
* 2. page contains the low 16-bit part of the 32-bit E1 words
*
* In each 16KB page we assume the start of the boot loader code
* in the highest 2KB part (at offset 0x3800);
* the rest (0x0000..0x37FF) is assumed to contain 0 bytes.
*/
#define POF_BOOT_LOADER_PAGE_SIZE 0x4000 /* =16384U */
#define POF_BOOT_LOADER_TOTAL_SIZE (2U*POF_BOOT_LOADER_PAGE_SIZE)
#define POF_BOOT_LOADER_CODE_SIZE 0x0800 /* =2KB =2048U */
/* offset in boot page, where loader code may start */
/* =0x3800= 14336U */
#define POF_BOOT_LOADER_OFF_IN_PAGE (POF_BOOT_LOADER_PAGE_SIZE-POF_BOOT_LOADER_CODE_SIZE)
/*--------------------------------------POF file record structs------------*/
typedef struct PofFileHdr_tag { /* Pof file header */
/*00 */ ulong Magic __attribute__((packed));
/*04 */ ulong N_PofRecs __attribute__((packed));
/*08 */
} tPofFileHdr;
typedef struct PofRecHdr_tag { /* Pof record header */
/*00 */ word PofRecId __attribute__((packed));
/*02 */ ulong PofRecDataLen __attribute__((packed));
/*06 */
} tPofRecHdr;
typedef struct PofTimeStamp_tag {
/*00 */ ulong UnixTime __attribute__((packed));
/*04 */ uchar DateTimeText[0x28] __attribute__((packed));
/* =40 */
/*2C */
} tPofTimeStamp;
/* tPofFileHdr.Magic value: */
#define TAGFILEMAGIC 0x464F501AUL
/* tPofRecHdr.PofRecId values: */
#define TAG_ABSDATA 0x1000 /* abs. data */
#define TAG_BOOTDTA 0x1001 /* boot data */
#define TAG_COMMENT 0x0020
#define TAG_SYSCALL 0x0021
#define TAG_FLOWCTRL 0x0022
#define TAG_TIMESTMP 0x0010 /* date/time stamp of version */
#define TAG_CABSDATA 0x1100 /* crypted abs. data */
#define TAG_CBOOTDTA 0x1101 /* crypted boot data */

View File

@ -0,0 +1,494 @@
/* $Id$
* Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* 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$
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/pci.h>
#include "hysdn_defs.h"
static char *hysdn_procconf_revision = "$Revision$";
#define INFO_OUT_LEN 80 /* length of info line including lf */
/********************************************************/
/* defines and data structure for conf write operations */
/********************************************************/
#define CONF_STATE_DETECT 0 /* waiting for detect */
#define CONF_STATE_CONF 1 /* writing config data */
#define CONF_STATE_POF 2 /* writing pof data */
#define CONF_LINE_LEN 80 /* 80 chars max */
struct conf_writedata {
hysdn_card *card; /* card the device is connected to */
int buf_size; /* actual number of bytes in the buffer */
int needed_size; /* needed size when reading pof */
int state; /* actual interface states from above constants */
uchar conf_line[CONF_LINE_LEN]; /* buffered conf line */
word channel; /* active channel number */
uchar *pof_buffer; /* buffer when writing pof */
};
/***********************************************************************/
/* process_line parses one config line and transfers it to the card if */
/* necessary. */
/* if the return value is negative an error occured. */
/***********************************************************************/
static int
process_line(struct conf_writedata *cnf)
{
uchar *cp = cnf->conf_line;
int i;
if (cnf->card->debug_flags & LOG_CNF_LINE)
hysdn_addlog(cnf->card, "conf line: %s", cp);
if (*cp == '-') { /* option */
cp++; /* point to option char */
if (*cp++ != 'c')
return (0); /* option unknown or used */
i = 0; /* start value for channel */
while ((*cp <= '9') && (*cp >= '0'))
i = i * 10 + *cp++ - '0'; /* get decimal number */
if (i > 65535) {
if (cnf->card->debug_flags & LOG_CNF_MISC)
hysdn_addlog(cnf->card, "conf channel invalid %d", i);
return (-ERR_INV_CHAN); /* invalid channel */
}
cnf->channel = i & 0xFFFF; /* set new channel number */
return (0); /* success */
} /* option */
if (*cp == '*') { /* line to send */
if (cnf->card->debug_flags & LOG_CNF_DATA)
hysdn_addlog(cnf->card, "conf chan=%d %s", cnf->channel, cp);
return (hysdn_tx_cfgline(cnf->card, cnf->conf_line + 1,
cnf->channel)); /* send the line without * */
} /* line to send */
return (0);
} /* process_line */
/*************************/
/* dummy file operations */
/*************************/
static loff_t
hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
{
return -ESPIPE;
} /* hysdn_dummy_lseek */
/***********************************/
/* conf file operations and tables */
/***********************************/
/****************************************************/
/* write conf file -> boot or send cfg line to card */
/****************************************************/
static ssize_t
hysdn_conf_write(struct file *file, const char *buf, size_t count, loff_t * off)
{
struct conf_writedata *cnf;
int i;
uchar ch, *cp;
if (&file->f_pos != off) /* fs error check */
return (-ESPIPE);
if (!count)
return (0); /* nothing to handle */
if (!(cnf = file->private_data))
return (-EFAULT); /* should never happen */
if (cnf->state == CONF_STATE_DETECT) { /* auto detect cnf or pof data */
if (copy_from_user(&ch, buf, 1)) /* get first char for detect */
return (-EFAULT);
if (ch == 0x1A) {
/* we detected a pof file */
if ((cnf->needed_size = pof_write_open(cnf->card, &cnf->pof_buffer)) <= 0)
return (cnf->needed_size); /* an error occured -> exit */
cnf->buf_size = 0; /* buffer is empty */
cnf->state = CONF_STATE_POF; /* new state */
} else {
/* conf data has been detected */
cnf->buf_size = 0; /* buffer is empty */
cnf->state = CONF_STATE_CONF; /* requested conf data write */
if (cnf->card->state != CARD_STATE_RUN)
return (-ERR_NOT_BOOTED);
cnf->conf_line[CONF_LINE_LEN - 1] = 0; /* limit string length */
cnf->channel = 4098; /* default channel for output */
}
} /* state was auto detect */
if (cnf->state == CONF_STATE_POF) { /* pof write active */
i = cnf->needed_size - cnf->buf_size; /* bytes still missing for write */
if (i <= 0)
return (-EINVAL); /* size error handling pof */
if (i < count)
count = i; /* limit requested number of bytes */
if (copy_from_user(cnf->pof_buffer + cnf->buf_size, buf, count))
return (-EFAULT); /* error while copying */
cnf->buf_size += count;
if (cnf->needed_size == cnf->buf_size) {
cnf->needed_size = pof_write_buffer(cnf->card, cnf->buf_size); /* write data */
if (cnf->needed_size <= 0) {
cnf->card->state = CARD_STATE_BOOTERR; /* show boot error */
return (cnf->needed_size); /* an error occured */
}
cnf->buf_size = 0; /* buffer is empty again */
}
}
/* pof write active */
else { /* conf write active */
if (cnf->card->state != CARD_STATE_RUN) {
if (cnf->card->debug_flags & LOG_CNF_MISC)
hysdn_addlog(cnf->card, "cnf write denied -> not booted");
return (-ERR_NOT_BOOTED);
}
i = (CONF_LINE_LEN - 1) - cnf->buf_size; /* bytes available in buffer */
if (i > 0) {
/* copy remaining bytes into buffer */
if (count > i)
count = i; /* limit transfer */
if (copy_from_user(cnf->conf_line + cnf->buf_size, buf, count))
return (-EFAULT); /* error while copying */
i = count; /* number of chars in buffer */
cp = cnf->conf_line + cnf->buf_size;
while (i) {
/* search for end of line */
if ((*cp < ' ') && (*cp != 9))
break; /* end of line found */
cp++;
i--;
} /* search for end of line */
if (i) {
/* delimiter found */
*cp++ = 0; /* string termination */
count -= (i - 1); /* subtract remaining bytes from count */
while ((i) && (*cp < ' ') && (*cp != 9)) {
i--; /* discard next char */
count++; /* mark as read */
cp++; /* next char */
}
cnf->buf_size = 0; /* buffer is empty after transfer */
if ((i = process_line(cnf)) < 0) /* handle the line */
count = i; /* return the error */
}
/* delimiter found */
else {
cnf->buf_size += count; /* add chars to string */
if (cnf->buf_size >= CONF_LINE_LEN - 1) {
if (cnf->card->debug_flags & LOG_CNF_MISC)
hysdn_addlog(cnf->card, "cnf line too long %d chars pos %d", cnf->buf_size, count);
return (-ERR_CONF_LONG);
}
} /* not delimited */
}
/* copy remaining bytes into buffer */
else {
if (cnf->card->debug_flags & LOG_CNF_MISC)
hysdn_addlog(cnf->card, "cnf line too long");
return (-ERR_CONF_LONG);
}
} /* conf write active */
return (count);
} /* hysdn_conf_write */
/*******************************************/
/* read conf file -> output card info data */
/*******************************************/
static ssize_t
hysdn_conf_read(struct file *file, char *buf, size_t count, loff_t * off)
{
char *cp;
int i;
if (off != &file->f_pos) /* fs error check */
return -ESPIPE;
if (file->f_mode & FMODE_READ) {
if (!(cp = file->private_data))
return (-EFAULT); /* should never happen */
i = strlen(cp); /* get total string length */
if (*off < i) {
/* still bytes to transfer */
cp += *off; /* point to desired data offset */
i -= *off; /* remaining length */
if (i > count)
i = count; /* limit length to transfer */
if (copy_to_user(buf, cp, i))
return (-EFAULT); /* copy error */
*off += i; /* adjust offset */
} else
return (0);
} else
return (-EPERM); /* no permission to read */
return (i);
} /* hysdn_conf_read */
/******************/
/* open conf file */
/******************/
static int
hysdn_conf_open(struct inode *ino, struct file *filep)
{
hysdn_card *card;
struct proc_dir_entry *pd;
struct conf_writedata *cnf;
char *cp, *tmp;
MOD_INC_USE_COUNT; /* lock module */
/* now search the addressed card */
card = card_root;
while (card) {
pd = card->procconf;
if (pd->low_ino == (ino->i_ino & 0xFFFF))
break;
card = card->next; /* search next entry */
}
if (!card) {
MOD_DEC_USE_COUNT; /* unlock module */
return (-ENODEV); /* device is unknown/invalid */
}
if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x",
filep->f_uid, filep->f_gid, filep->f_mode);
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> write boot file or conf line */
if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) {
MOD_DEC_USE_COUNT;
return (-EFAULT);
}
cnf->card = card;
cnf->buf_size = 0; /* nothing buffered */
cnf->state = CONF_STATE_DETECT; /* start auto detect */
filep->private_data = cnf;
} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
/* read access -> output card info data */
if (!(tmp = (char *) kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) {
MOD_DEC_USE_COUNT;
return (-EFAULT); /* out of memory */
}
filep->private_data = tmp; /* start of string */
/* first output a headline */
sprintf(tmp, "id bus slot type irq iobase dp-mem b-chans fax-chans state device");
cp = tmp; /* start of string */
while (*cp)
cp++;
while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
*cp++ = ' ';
*cp++ = '\n';
/* and now the data */
sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x %7d %9d %3d %s",
card->myid,
card->bus,
PCI_SLOT(card->devfn),
card->brdtype,
card->irq,
card->iobase,
card->membase,
card->bchans,
card->faxchans,
card->state,
hysdn_net_getname(card));
while (*cp)
cp++;
while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
*cp++ = ' ';
*cp++ = '\n';
*cp = 0; /* end of string */
} else { /* simultaneous read/write access forbidden ! */
MOD_DEC_USE_COUNT; /* unlock module */
return (-EPERM); /* no permission this time */
}
return (0);
} /* hysdn_conf_open */
/***************************/
/* close a config file. */
/***************************/
static int
hysdn_conf_close(struct inode *ino, struct file *filep)
{
hysdn_card *card;
struct conf_writedata *cnf;
int retval = 0;
struct proc_dir_entry *pd;
/* search the addressed card */
card = card_root;
while (card) {
pd = card->procconf;
if (pd->low_ino == (ino->i_ino & 0xFFFF))
break;
card = card->next; /* search next entry */
}
if (!card) {
return (-ENODEV); /* device is unknown/invalid */
}
if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x",
filep->f_uid, filep->f_gid, filep->f_mode);
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> write boot file or conf line */
if (filep->private_data) {
cnf = filep->private_data;
if (cnf->state == CONF_STATE_POF)
retval = pof_write_close(cnf->card); /* close the pof write */
kfree(filep->private_data); /* free allocated memory for buffer */
} /* handle write private data */
} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
/* read access -> output card info data */
if (filep->private_data)
kfree(filep->private_data); /* release memory */
}
MOD_DEC_USE_COUNT; /* reduce usage count */
return (retval);
} /* hysdn_conf_close */
/******************************************************/
/* table for conf filesystem functions defined above. */
/******************************************************/
static struct file_operations conf_fops =
{
hysdn_dummy_lseek,
hysdn_conf_read,
hysdn_conf_write,
NULL, /* readdir */
NULL, /* poll */
NULL, /* ioctl */
NULL, /* mmap */
hysdn_conf_open,
NULL, /* flush */
hysdn_conf_close,
NULL /* fsync */
};
static struct inode_operations conf_inode_operations =
{
&conf_fops, /* log proc file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
/*****************************/
/* hysdn subdir in /proc/net */
/*****************************/
struct proc_dir_entry *hysdn_proc_entry = NULL;
/*******************************************************************************/
/* hysdn_procconf_init is called when the module is loaded and after the cards */
/* have been detected. The needed proc dir and card config files are created. */
/* The log init is called at last. */
/*******************************************************************************/
int
hysdn_procconf_init(void)
{
hysdn_card *card;
uchar conf_name[20];
hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
if (!hysdn_proc_entry) {
printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
return (-1);
}
card = card_root; /* point to first card */
while (card) {
sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
if ((card->procconf = (void *) create_proc_entry(conf_name,
S_IFREG | S_IRUGO | S_IWUSR,
hysdn_proc_entry)) != NULL) {
((struct proc_dir_entry *) card->procconf)->ops = &conf_inode_operations;
hysdn_proclog_init(card); /* init the log file entry */
}
card = card->next; /* next entry */
}
printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procconf_revision));
return (0);
} /* hysdn_procconf_init */
/*************************************************************************************/
/* hysdn_procconf_release is called when the module is unloaded and before the cards */
/* resources are released. The module counter is assumed to be 0 ! */
/*************************************************************************************/
void
hysdn_procconf_release(void)
{
hysdn_card *card;
uchar conf_name[20];
card = card_root; /* start with first card */
while (card) {
sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
if (card->procconf)
remove_proc_entry(conf_name, hysdn_proc_entry);
hysdn_proclog_release(card); /* init the log file entry */
card = card->next; /* point to next card */
}
remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
} /* hysdn_procfs_release */

View File

@ -0,0 +1,505 @@
/* $Id$
* Linux driver for HYSDN cards, /proc/net filesystem log functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* 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$
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/pci.h>
#include "hysdn_defs.h"
static char *hysdn_procfs_revision = "$Revision$";
#define INFO_OUT_LEN 80 /* length of info line including lf */
/*************************************************/
/* structure keeping ascii log for device output */
/*************************************************/
struct log_data {
struct log_data *next;
ulong usage_cnt; /* number of files still to work */
void *proc_ctrl; /* pointer to own control procdata structure */
char log_start[2]; /* log string start (final len aligned by size) */
};
/**********************************************/
/* structure holding proc entrys for one card */
/**********************************************/
struct procdata {
struct proc_dir_entry *log; /* log entry */
char log_name[15]; /* log filename */
struct log_data *log_head, *log_tail; /* head and tail for queue */
int if_used; /* open count for interface */
#ifdef COMPAT_HAS_NEW_WAITQ
wait_queue_head_t rd_queue;
#else
struct wait_queue *rd_queue; /* wait queue structure */
#endif
};
/********************************************/
/* put an log buffer into the log queue. */
/* This buffer will be kept until all files */
/* opened for read got the contents. */
/* Flushes buffers not longer in use. */
/********************************************/
void
put_log_buffer(hysdn_card * card, char *cp)
{
struct log_data *ib;
struct procdata *pd = card->procfs;
int flags;
if (!pd)
return;
if (!cp)
return;
if (!*cp)
return;
if (pd->if_used <= 0)
return; /* no open file for read */
if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
return; /* no memory */
strcpy(ib->log_start, cp); /* set output string */
ib->next = NULL;
ib->proc_ctrl = pd; /* point to own control structure */
save_flags(flags);
cli();
ib->usage_cnt = pd->if_used;
if (!pd->log_head)
pd->log_head = ib; /* new head */
else
pd->log_tail->next = ib; /* follows existing messages */
pd->log_tail = ib; /* new tail */
restore_flags(flags);
/* delete old entrys */
while (pd->log_head->next) {
if ((pd->log_head->usage_cnt <= 0) &&
(pd->log_head->next->usage_cnt <= 0)) {
ib = pd->log_head;
pd->log_head = pd->log_head->next;
kfree(ib);
} else
break;
} /* pd->log_head->next */
wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */
} /* put_log_buffer */
/*************************/
/* dummy file operations */
/*************************/
static loff_t
hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
{
return -ESPIPE;
} /* hysdn_dummy_lseek */
/**********************************/
/* log file operations and tables */
/**********************************/
/****************************************/
/* write log file -> set log level bits */
/****************************************/
static ssize_t
hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off)
{
int retval;
hysdn_card *card = (hysdn_card *) file->private_data;
if (&file->f_pos != off) /* fs error check */
return (-ESPIPE);
if ((retval = pof_boot_write(card, buf, count)) < 0)
retval = -EFAULT; /* an error occured */
return (retval);
} /* hysdn_log_write */
/******************/
/* read log file */
/******************/
static ssize_t
hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off)
{
struct log_data *inf;
int len;
word ino;
struct procdata *pd;
hysdn_card *card;
if (!*((struct log_data **) file->private_data)) {
if (file->f_flags & O_NONBLOCK)
return (-EAGAIN);
/* sorry, but we need to search the card */
ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
card = card_root;
while (card) {
pd = card->procfs;
if (pd->log->low_ino == ino)
break;
card = card->next; /* search next entry */
}
if (card)
interruptible_sleep_on(&(pd->rd_queue));
else
return (-EAGAIN);
}
if (!(inf = *((struct log_data **) file->private_data)))
return (0);
inf->usage_cnt--; /* new usage count */
(struct log_data **) file->private_data = &inf->next; /* next structure */
if ((len = strlen(inf->log_start)) <= count) {
if (copy_to_user(buf, inf->log_start, len))
return -EFAULT;
file->f_pos += len;
return (len);
}
return (0);
} /* hysdn_log_read */
/******************/
/* open log file */
/******************/
static int
hysdn_log_open(struct inode *ino, struct file *filep)
{
hysdn_card *card;
struct procdata *pd;
ulong flags;
MOD_INC_USE_COUNT; /* lock module */
card = card_root;
while (card) {
pd = card->procfs;
if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
break;
card = card->next; /* search next entry */
}
if (!card) {
MOD_DEC_USE_COUNT; /* unlock module */
return (-ENODEV); /* device is unknown/invalid */
}
filep->private_data = card; /* remember our own card */
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> boot pof data */
if (pof_boot_open(card)) {
MOD_DEC_USE_COUNT; /* unlock module */
return (-EPERM); /* no permission this time */
}
} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
/* read access -> log/debug read */
save_flags(flags);
cli();
pd->if_used++;
if (pd->log_head)
(struct log_data **) filep->private_data = &(pd->log_tail->next);
else
(struct log_data **) filep->private_data = &(pd->log_head);
restore_flags(flags);
} else { /* simultaneous read/write access forbidden ! */
MOD_DEC_USE_COUNT; /* unlock module */
return (-EPERM); /* no permission this time */
}
return (0);
} /* hysdn_log_open */
/*******************************************************************************/
/* close a cardlog file. If the file has been opened for exclusive write it is */
/* assumed as pof data input and the pof loader is noticed about. */
/* Otherwise file is handled as log output. In this case the interface usage */
/* count is decremented and all buffers are noticed of closing. If this file */
/* was the last one to be closed, all buffers are freed. */
/*******************************************************************************/
static int
hysdn_log_close(struct inode *ino, struct file *filep)
{
struct log_data *inf;
struct procdata *pd;
hysdn_card *card;
int flags, retval = 0;
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> write debug completely written */
retval = 0; /* success */
} else {
/* read access -> log/debug read, mark one further file as closed */
pd = NULL;
save_flags(flags);
cli();
inf = *((struct log_data **) filep->private_data); /* get first log entry */
if (inf)
pd = (struct procdata *) inf->proc_ctrl; /* still entries there */
else {
/* no info available -> search card */
card = card_root;
while (card) {
pd = card->procfs;
if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
break;
card = card->next; /* search next entry */
}
if (card)
pd = card->procfs; /* pointer to procfs ctrl */
}
if (pd)
pd->if_used--; /* decrement interface usage count by one */
while (inf) {
inf->usage_cnt--; /* decrement usage count for buffers */
inf = inf->next;
}
restore_flags(flags);
if (pd)
if (pd->if_used <= 0) /* delete buffers if last file closed */
while (pd->log_head) {
inf = pd->log_head;
pd->log_head = pd->log_head->next;
kfree(inf);
}
} /* read access */
MOD_DEC_USE_COUNT;
return (retval);
} /* hysdn_log_close */
/*************************************************/
/* select/poll routine to be able using select() */
/*************************************************/
static unsigned int
hysdn_log_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
word ino;
hysdn_card *card;
struct procdata *pd;
if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
return (mask); /* no polling for write supported */
/* we need to search the card */
ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
card = card_root;
while (card) {
pd = card->procfs;
if (pd->log->low_ino == ino)
break;
card = card->next; /* search next entry */
}
if (!card)
return (mask); /* card not found */
poll_wait(file, &(pd->rd_queue), wait);
if (*((struct log_data **) file->private_data))
mask |= POLLIN | POLLRDNORM;
return mask;
} /* hysdn_log_poll */
/**************************************************/
/* table for log filesystem functions defined above. */
/**************************************************/
static struct file_operations log_fops =
{
hysdn_dummy_lseek,
hysdn_log_read,
hysdn_log_write,
NULL, /* readdir */
hysdn_log_poll, /* poll */
NULL, /*hysdn_log_ioctl, *//* ioctl */
NULL, /* mmap */
hysdn_log_open,
NULL, /* flush */
hysdn_log_close,
NULL /* fsync */
};
struct inode_operations log_inode_operations =
{
&log_fops, /* log proc file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
/*****************************************/
/* Output info data to the cardinfo file */
/*****************************************/
static int
info_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
{
char tmp[INFO_OUT_LEN * 11 + 2];
int i;
char *cp;
hysdn_card *card;
sprintf(tmp, "id bus slot type irq iobase plx-mem dp-mem boot device");
cp = tmp; /* start of string */
while (*cp)
cp++;
while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
*cp++ = ' ';
*cp++ = '\n';
card = card_root; /* start of list */
while (card) {
sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x 0x%08x",
card->myid,
card->bus,
PCI_SLOT(card->devfn),
card->brdtype,
card->irq,
card->iobase,
card->plxbase,
card->membase);
card = card->next;
while (*cp)
cp++;
while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
*cp++ = ' ';
*cp++ = '\n';
}
i = cp - tmp;
*start = buffer;
if (offset + length > i) {
length = i - offset;
*eof = 1;
} else if (offset > i) {
length = 0;
*eof = 1;
}
cp = tmp + offset;
if (length > 0) {
/* start_bh_atomic(); */
memcpy(buffer, cp, length);
/* end_bh_atomic(); */
return length;
}
return 0;
} /* info_read */
/*****************************/
/* hysdn subdir in /proc/net */
/*****************************/
static struct proc_dir_entry *hysdn_proc_entry = NULL;
static struct proc_dir_entry *hysdn_info_entry = NULL;
/***************************************************************************************/
/* hysdn_procfs_init is called when the module is loaded and after the cards have been */
/* detected. The needed proc dir and card entries are created. */
/***************************************************************************************/
int
hysdn_procfs_init(void)
{
struct procdata *pd;
hysdn_card *card;
hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
if (!hysdn_proc_entry) {
printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
return (-1);
}
hysdn_info_entry = create_proc_entry("cardinfo", 0, hysdn_proc_entry);
if (hysdn_info_entry)
hysdn_info_entry->read_proc = info_read; /* read info function */
/* create all cardlog proc entries */
card = card_root; /* start with first card */
while (card) {
if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
memset(pd, 0, sizeof(struct procdata));
sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL)
pd->log->ops = &log_inode_operations; /* set new operations table */
#ifdef COMPAT_HAS_NEW_WAITQ
init_waitqueue_head(&(pd->rd_queue));
#endif
card->procfs = (void *) pd; /* remember procfs structure */
}
card = card->next; /* point to next card */
}
printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procfs_revision));
return (0);
} /* hysdn_procfs_init */
/***************************************************************************************/
/* hysdn_procfs_release is called when the module is unloaded and before the cards */
/* resources are released. The module counter is assumed to be 0 ! */
/***************************************************************************************/
void
hysdn_procfs_release(void)
{
struct procdata *pd;
hysdn_card *card;
card = card_root; /* start with first card */
while (card) {
if ((pd = (struct procdata *) card->procfs) != NULL) {
if (pd->log)
remove_proc_entry(pd->log_name, hysdn_proc_entry);
kfree(pd); /* release memory */
}
card = card->next; /* point to next card */
}
remove_proc_entry("cardinfo", hysdn_proc_entry);
remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
} /* hysdn_procfs_release */

View File

@ -0,0 +1,497 @@
/* $Id$
* Linux driver for HYSDN cards, /proc/net filesystem log functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* 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$
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/pci.h>
#include "hysdn_defs.h"
static char *hysdn_proclog_revision = "$Revision$";
/* the proc subdir for the interface is defined in the procconf module */
extern struct proc_dir_entry *hysdn_proc_entry;
/*************************************************/
/* structure keeping ascii log for device output */
/*************************************************/
struct log_data {
struct log_data *next;
ulong usage_cnt; /* number of files still to work */
void *proc_ctrl; /* pointer to own control procdata structure */
char log_start[2]; /* log string start (final len aligned by size) */
};
/**********************************************/
/* structure holding proc entrys for one card */
/**********************************************/
struct procdata {
struct proc_dir_entry *log; /* log entry */
char log_name[15]; /* log filename */
struct log_data *log_head, *log_tail; /* head and tail for queue */
int if_used; /* open count for interface */
int volatile del_lock; /* lock for delete operations */
uchar logtmp[LOG_MAX_LINELEN];
#ifdef COMPAT_HAS_NEW_WAITQ
wait_queue_head_t rd_queue;
#else
struct wait_queue *rd_queue; /* wait queue structure */
#endif
};
/**********************************************/
/* log function for cards error log interface */
/**********************************************/
void
hysdn_card_errlog(hysdn_card * card, tErrLogEntry * logp, int maxsize)
{
char buf[ERRLOG_TEXT_SIZE + 40];
sprintf(buf, "LOG 0x%08lX 0x%08lX : %s\n", logp->ulErrType, logp->ulErrSubtype, logp->ucText);
put_log_buffer(card, buf); /* output the string */
} /* hysdn_card_errlog */
/***************************************************/
/* Log function using format specifiers for output */
/***************************************************/
void
hysdn_addlog(hysdn_card * card, char *fmt,...)
{
struct procdata *pd = card->proclog;
char *cp;
va_list args;
if (!pd)
return; /* log structure non existent */
cp = pd->logtmp;
cp += sprintf(cp, "HYSDN: card %d ", card->myid);
va_start(args, fmt);
cp += vsprintf(cp, fmt, args);
va_end(args);
*cp++ = '\n';
*cp = 0;
if (card->debug_flags & DEB_OUT_SYSLOG)
printk(KERN_INFO "%s", pd->logtmp);
else
put_log_buffer(card, pd->logtmp);
} /* hysdn_addlog */
/********************************************/
/* put an log buffer into the log queue. */
/* This buffer will be kept until all files */
/* opened for read got the contents. */
/* Flushes buffers not longer in use. */
/********************************************/
void
put_log_buffer(hysdn_card * card, char *cp)
{
struct log_data *ib;
struct procdata *pd = card->proclog;
int i, flags;
if (!pd)
return;
if (!cp)
return;
if (!*cp)
return;
if (pd->if_used <= 0)
return; /* no open file for read */
if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
return; /* no memory */
strcpy(ib->log_start, cp); /* set output string */
ib->next = NULL;
ib->proc_ctrl = pd; /* point to own control structure */
save_flags(flags);
cli();
ib->usage_cnt = pd->if_used;
if (!pd->log_head)
pd->log_head = ib; /* new head */
else
pd->log_tail->next = ib; /* follows existing messages */
pd->log_tail = ib; /* new tail */
i = pd->del_lock++; /* get lock state */
restore_flags(flags);
/* delete old entrys */
if (!i)
while (pd->log_head->next) {
if ((pd->log_head->usage_cnt <= 0) &&
(pd->log_head->next->usage_cnt <= 0)) {
ib = pd->log_head;
pd->log_head = pd->log_head->next;
kfree(ib);
} else
break;
} /* pd->log_head->next */
pd->del_lock--; /* release lock level */
wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */
} /* put_log_buffer */
/*************************/
/* dummy file operations */
/*************************/
static loff_t
hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
{
return -ESPIPE;
} /* hysdn_dummy_lseek */
/******************************/
/* file operations and tables */
/******************************/
/****************************************/
/* write log file -> set log level bits */
/****************************************/
static ssize_t
hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off)
{
ulong u = 0;
int found = 0;
uchar *cp, valbuf[128];
long base = 10;
hysdn_card *card = (hysdn_card *) file->private_data;
if (&file->f_pos != off) /* fs error check */
return (-ESPIPE);
if (count > (sizeof(valbuf) - 1))
count = sizeof(valbuf) - 1; /* limit length */
if (copy_from_user(valbuf, buf, count))
return (-EFAULT); /* copy failed */
valbuf[count] = 0; /* terminating 0 */
cp = valbuf;
if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) {
cp += 2; /* pointer after hex modifier */
base = 16;
}
/* scan the input for debug flags */
while (*cp) {
if ((*cp >= '0') && (*cp <= '9')) {
found = 1;
u *= base; /* adjust to next digit */
u += *cp++ - '0';
continue;
}
if (base != 16)
break; /* end of number */
if ((*cp >= 'a') && (*cp <= 'f')) {
found = 1;
u *= base; /* adjust to next digit */
u += *cp++ - 'a' + 10;
continue;
}
break; /* terminated */
}
if (found) {
card->debug_flags = u; /* remember debug flags */
hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags);
}
return (count);
} /* hysdn_log_write */
/******************/
/* read log file */
/******************/
static ssize_t
hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off)
{
struct log_data *inf;
int len;
word ino;
struct procdata *pd;
hysdn_card *card;
if (!*((struct log_data **) file->private_data)) {
if (file->f_flags & O_NONBLOCK)
return (-EAGAIN);
/* sorry, but we need to search the card */
ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
card = card_root;
while (card) {
pd = card->proclog;
if (pd->log->low_ino == ino)
break;
card = card->next; /* search next entry */
}
if (card)
interruptible_sleep_on(&(pd->rd_queue));
else
return (-EAGAIN);
}
if (!(inf = *((struct log_data **) file->private_data)))
return (0);
inf->usage_cnt--; /* new usage count */
(struct log_data **) file->private_data = &inf->next; /* next structure */
if ((len = strlen(inf->log_start)) <= count) {
if (copy_to_user(buf, inf->log_start, len))
return -EFAULT;
file->f_pos += len;
return (len);
}
return (0);
} /* hysdn_log_read */
/******************/
/* open log file */
/******************/
static int
hysdn_log_open(struct inode *ino, struct file *filep)
{
hysdn_card *card;
struct procdata *pd;
ulong flags;
MOD_INC_USE_COUNT; /* lock module */
card = card_root;
while (card) {
pd = card->proclog;
if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
break;
card = card->next; /* search next entry */
}
if (!card) {
MOD_DEC_USE_COUNT; /* unlock module */
return (-ENODEV); /* device is unknown/invalid */
}
filep->private_data = card; /* remember our own card */
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> write log level only */
} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
/* read access -> log/debug read */
save_flags(flags);
cli();
pd->if_used++;
if (pd->log_head)
(struct log_data **) filep->private_data = &(pd->log_tail->next);
else
(struct log_data **) filep->private_data = &(pd->log_head);
restore_flags(flags);
} else { /* simultaneous read/write access forbidden ! */
MOD_DEC_USE_COUNT; /* unlock module */
return (-EPERM); /* no permission this time */
}
return (0);
} /* hysdn_log_open */
/*******************************************************************************/
/* close a cardlog file. If the file has been opened for exclusive write it is */
/* assumed as pof data input and the pof loader is noticed about. */
/* Otherwise file is handled as log output. In this case the interface usage */
/* count is decremented and all buffers are noticed of closing. If this file */
/* was the last one to be closed, all buffers are freed. */
/*******************************************************************************/
static int
hysdn_log_close(struct inode *ino, struct file *filep)
{
struct log_data *inf;
struct procdata *pd;
hysdn_card *card;
int flags, retval = 0;
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> write debug level written */
retval = 0; /* success */
} else {
/* read access -> log/debug read, mark one further file as closed */
pd = NULL;
save_flags(flags);
cli();
inf = *((struct log_data **) filep->private_data); /* get first log entry */
if (inf)
pd = (struct procdata *) inf->proc_ctrl; /* still entries there */
else {
/* no info available -> search card */
card = card_root;
while (card) {
pd = card->proclog;
if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
break;
card = card->next; /* search next entry */
}
if (card)
pd = card->proclog; /* pointer to procfs log */
}
if (pd)
pd->if_used--; /* decrement interface usage count by one */
while (inf) {
inf->usage_cnt--; /* decrement usage count for buffers */
inf = inf->next;
}
restore_flags(flags);
if (pd)
if (pd->if_used <= 0) /* delete buffers if last file closed */
while (pd->log_head) {
inf = pd->log_head;
pd->log_head = pd->log_head->next;
kfree(inf);
}
} /* read access */
MOD_DEC_USE_COUNT;
return (retval);
} /* hysdn_log_close */
/*************************************************/
/* select/poll routine to be able using select() */
/*************************************************/
static unsigned int
hysdn_log_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
word ino;
hysdn_card *card;
struct procdata *pd;
if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
return (mask); /* no polling for write supported */
/* we need to search the card */
ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
card = card_root;
while (card) {
pd = card->proclog;
if (pd->log->low_ino == ino)
break;
card = card->next; /* search next entry */
}
if (!card)
return (mask); /* card not found */
poll_wait(file, &(pd->rd_queue), wait);
if (*((struct log_data **) file->private_data))
mask |= POLLIN | POLLRDNORM;
return mask;
} /* hysdn_log_poll */
/**************************************************/
/* table for log filesystem functions defined above. */
/**************************************************/
static struct file_operations log_fops =
{
hysdn_dummy_lseek,
hysdn_log_read,
hysdn_log_write,
NULL, /* readdir */
hysdn_log_poll, /* poll */
NULL,
NULL, /* mmap */
hysdn_log_open,
NULL, /* flush */
hysdn_log_close,
NULL /* fsync */
};
struct inode_operations log_inode_operations =
{
&log_fops, /* log proc file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
/***********************************************************************************/
/* hysdn_proclog_init is called when the module is loaded after creating the cards */
/* conf files.the cards have been */
/***********************************************************************************/
int
hysdn_proclog_init(hysdn_card * card)
{
struct procdata *pd;
/* create a cardlog proc entry */
if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
memset(pd, 0, sizeof(struct procdata));
sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL)
pd->log->ops = &log_inode_operations; /* set new operations table */
#ifdef COMPAT_HAS_NEW_WAITQ
init_waitqueue_head(&(pd->rd_queue));
#endif
card->proclog = (void *) pd; /* remember procfs structure */
}
return (0);
} /* hysdn_proclog_init */
/************************************************************************************/
/* hysdn_proclog_release is called when the module is unloaded and before the cards */
/* conf file is released */
/* The module counter is assumed to be 0 ! */
/************************************************************************************/
void
hysdn_proclog_release(hysdn_card * card)
{
struct procdata *pd;
if ((pd = (struct procdata *) card->proclog) != NULL) {
if (pd->log)
remove_proc_entry(pd->log_name, hysdn_proc_entry);
kfree(pd); /* release memory */
card->proclog = NULL;
}
} /* hysdn_proclog_release */

View File

@ -0,0 +1,199 @@
/* $Id$
* Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc.
*
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* 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$
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <asm/io.h>
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include "hysdn_defs.h"
/*****************************************************************************/
/* hysdn_sched_rx is called from the cards handler to announce new data is */
/* available from the card. The routine has to handle the data and return */
/* with a nonzero code if the data could be worked (or even thrown away), if */
/* no room to buffer the data is available a zero return tells the card */
/* to keep the data until later. */
/*****************************************************************************/
int
hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan)
{
switch (chan) {
case CHAN_NDIS_DATA:
hysdn_rx_netpkt(card, buf, len); /* give packet to network handler */
break;
case CHAN_ERRLOG:
hysdn_card_errlog(card, (tErrLogEntry *) buf, len);
if (card->err_log_state == ERRLOG_STATE_ON)
card->err_log_state = ERRLOG_STATE_START; /* start new fetch */
break;
default:
printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len);
break;
} /* switch rx channel */
return (1); /* always handled */
} /* hysdn_sched_rx */
/*****************************************************************************/
/* hysdn_sched_tx is called from the cards handler to announce that there is */
/* room in the tx-buffer to the card and data may be sent if needed. */
/* If the routine wants to send data it must fill buf, len and chan with the */
/* appropriate data and return a nonzero value. With a zero return no new */
/* data to send is assumed. maxlen specifies the buffer size available for */
/* sending. */
/*****************************************************************************/
int
hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile *chan, word maxlen)
{
struct sk_buff *skb;
if (card->net_tx_busy) {
card->net_tx_busy = 0; /* reset flag */
hysdn_tx_netack(card); /* acknowledge packet send */
} /* a network packet has completely been transferred */
/* first of all async requests are handled */
if (card->async_busy) {
if (card->async_len <= maxlen) {
memcpy(buf, card->async_data, card->async_len);
*len = card->async_len;
*chan = card->async_channel;
card->async_busy = 0; /* reset request */
return (1);
}
card->async_busy = 0; /* in case of length error */
} /* async request */
if ((card->err_log_state == ERRLOG_STATE_START) &&
(maxlen >= ERRLOG_CMD_REQ_SIZE)) {
strcpy(buf, ERRLOG_CMD_REQ); /* copy the command */
*len = ERRLOG_CMD_REQ_SIZE; /* buffer length */
*chan = CHAN_ERRLOG; /* and channel */
card->err_log_state = ERRLOG_STATE_ON; /* new state is on */
return (1); /* tell that data should be send */
} /* error log start and able to send */
if ((card->err_log_state == ERRLOG_STATE_STOP) &&
(maxlen >= ERRLOG_CMD_STOP_SIZE)) {
strcpy(buf, ERRLOG_CMD_STOP); /* copy the command */
*len = ERRLOG_CMD_STOP_SIZE; /* buffer length */
*chan = CHAN_ERRLOG; /* and channel */
card->err_log_state = ERRLOG_STATE_OFF; /* new state is off */
return (1); /* tell that data should be send */
} /* error log start and able to send */
/* now handle network interface packets */
if ((skb = hysdn_tx_netget(card)) != NULL) {
if (skb->len <= maxlen) {
memcpy(buf, skb->data, skb->len); /* copy the packet to the buffer */
*len = skb->len;
*chan = CHAN_NDIS_DATA;
card->net_tx_busy = 1; /* we are busy sending network data */
return (1); /* go and send the data */
} else
hysdn_tx_netack(card); /* aknowledge packet -> throw away */
} /* send a network packet if available */
return (0); /* nothing to send */
} /* hysdn_sched_tx */
/*****************************************************************************/
/* send one config line to the card and return 0 if successfull, otherwise a */
/* negative error code. */
/* The function works with timeouts perhaps not giving the greatest speed */
/* sending the line, but this should be meaningless beacuse only some lines */
/* are to be sent and this happens very seldom. */
/*****************************************************************************/
int
hysdn_tx_cfgline(hysdn_card * card, uchar * line, word chan)
{
int cnt = 50; /* timeout intervalls */
ulong flags;
if (card->debug_flags & LOG_SCHED_ASYN)
hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1);
save_flags(flags);
cli();
while (card->async_busy) {
sti();
if (card->debug_flags & LOG_SCHED_ASYN)
hysdn_addlog(card, "async tx-cfg delayed");
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
if (!--cnt) {
restore_flags(flags);
return (-ERR_ASYNC_TIME); /* timed out */
}
cli();
} /* wait for buffer to become free */
strcpy(card->async_data, line);
card->async_len = strlen(line) + 1;
card->async_channel = chan;
card->async_busy = 1; /* request transfer */
/* now queue the task */
queue_task(&card->irq_queue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
sti();
if (card->debug_flags & LOG_SCHED_ASYN)
hysdn_addlog(card, "async tx-cfg data queued");
cnt++; /* short delay */
cli();
while (card->async_busy) {
sti();
if (card->debug_flags & LOG_SCHED_ASYN)
hysdn_addlog(card, "async tx-cfg waiting for tx-ready");
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
if (!--cnt) {
restore_flags(flags);
return (-ERR_ASYNC_TIME); /* timed out */
}
cli();
} /* wait for buffer to become free again */
restore_flags(flags);
if (card->debug_flags & LOG_SCHED_ASYN)
hysdn_addlog(card, "async tx-cfg data send");
return (0); /* line send correctly */
} /* hysdn_tx_cfgline */

View File

@ -0,0 +1,132 @@
#ifndef __INCE1PC_H__
#define __INCE1PC_H__
/****************************************************************************
FILE: ince1pc.h
AUTHOR: M.Steinkopf
PURPOSE: common definitions for both sides of the bus:
- conventions both spoolers must know
- channel numbers agreed upon
*****************************************************************************/
/* basic scalar definitions have same meanning,
* but their declaration location depends on environment
*/
/*--------------------------------------channel numbers---------------------*/
#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */
#define CHAN_ERRLOG 0x0005 /* error logger */
#define CHAN_CAPI 0x0064 /* CAPI interface */
#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */
/*--------------------------------------POF ready msg-----------------------*/
/* NOTE: after booting POF sends system ready message to PC: */
#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */
#define RDY_MAGIC_SIZE 4 /* size in bytes */
#define MAX_N_TOK_BYTES 255
#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE
#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
#define SYSR_TOK_END 0
#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */
#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */
#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */
#define SYSR_TOK_ESC 255 /* undefined data size yet */
/* default values, if not corrected by token: */
#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */
#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */
/* syntax of new SYSR token stream:
* channel: CHAN_SYSTEM
* msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE
* RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
* msg : 0 1 2 3 {4 5 6 ..}
* S Y S R MAX_N_TOK_BYTES bytes of TokenStream
*
* TokenStream := empty
* | {NonEndTokenChunk} EndToken RotlCRC
* NonEndTokenChunk:= NonEndTokenId DataLen [Data]
* NonEndTokenId := 0x01 .. 0xFE 1 BYTE
* DataLen := 0x00 .. 0xFF 1 BYTE
* Data := DataLen bytes
* EndToken := 0x00
* RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes
* s. RotlCRC algorithm
*
* RotlCRC algorithm:
* ucSum= 0 1 uchar
* for all NonEndTokenChunk bytes:
* ROTL(ucSum,1) rotate left by 1
* ucSum += Char; add current byte with swap around
* RotlCRC= ~ucSum; invert all bits for result
*
* note:
* - for 16-bit FIFO add padding 0 byte to achieve even token data bytes!
*/
/*--------------------------------------error logger------------------------*/
/* note: pof needs final 0 ! */
#define ERRLOG_CMD_REQ "ERRLOG ON"
#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */
#define ERRLOG_CMD_STOP "ERRLOG OFF"
#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */
#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */
/* remaining text size = 55 */
#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1)
typedef struct ErrLogEntry_tag {
/*00 */ ulong ulErrType;
/*04 */ ulong ulErrSubtype;
/*08 */ uchar ucTextSize;
/*09 */ uchar ucText[ERRLOG_TEXT_SIZE];
/* ASCIIZ of len ucTextSize-1 */
/*40 */
} tErrLogEntry;
#if defined(__TURBOC__)
#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE
#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE
#endif /* */
#endif /* */
/*--------------------------------------DPRAM boot spooler------------------*/
/* this is the struture used between pc and
* hyperstone to exchange boot data
*/
#define DPRAM_SPOOLER_DATA_SIZE 0x20
typedef struct DpramBootSpooler_tag {
/*00 */ uchar Len;
/*01 */ volatile uchar RdPtr;
/*02 */ uchar WrPtr;
/*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE];
/*23 */
} tDpramBootSpooler;
#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */
#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */
/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/
/* at DPRAM offset 0x1C00: */
#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */
#endif /* __INCE1PC_H__ */

45
include/linux/hysdn_if.h Normal file
View File

@ -0,0 +1,45 @@
/* $Id$
* Linux driver for HYSDN cards, ioctl definitions shared by hynetmgr and driver.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* 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$
*
*/
/****************/
/* error values */
/****************/
#define ERR_NONE 0 /* no error occured */
#define ERR_ALREADY_BOOT 1000 /* we are already booting */
#define EPOF_BAD_MAGIC 1001 /* bad magic in POF header */
#define ERR_BOARD_DPRAM 1002 /* board DPRAM failed */
#define EPOF_INTERNAL 1003 /* internal POF handler error */
#define EPOF_BAD_IMG_SIZE 1004 /* POF boot image size invalid */
#define ERR_BOOTIMG_FAIL 1005 /* 1. stage boot image did not start */
#define ERR_BOOTSEQ_FAIL 1006 /* 2. stage boot seq handshake timeout */
#define ERR_POF_TIMEOUT 1007 /* timeout waiting for card pof ready */
#define ERR_NOT_BOOTED 1008 /* operation only allowed when booted */
#define ERR_CONF_LONG 1009 /* conf line is to long */
#define ERR_INV_CHAN 1010 /* invalid channel number */
#define ERR_ASYNC_TIME 1011 /* timeout sending async data */