![Masanari Iida](/assets/img/avatar_default.png)
Correct spelling typo in comments. Signed-off-by: Masanari Iida <standby24x7@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1374 lines
31 KiB
C
1374 lines
31 KiB
C
/*
|
|
* Copyright 2003 Digi International (www.digi.com)
|
|
* Scott H Kilau <Scott_Kilau at digi dot com>
|
|
*
|
|
* 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, EXPRESS OR IMPLIED; 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.
|
|
*
|
|
*
|
|
* NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
|
|
*
|
|
* This is shared code between Digi's CVS archive and the
|
|
* Linux Kernel sources.
|
|
* Changing the source just for reformatting needlessly breaks
|
|
* our CVS diff history.
|
|
*
|
|
* Send any bug fixes/changes to: Eng.Linux at digi dot com.
|
|
* Thank you.
|
|
*
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* dgap_parse.c - Parses the configuration information from the input file.
|
|
*
|
|
* $Id: dgap_parse.c,v 1.1 2009/10/23 14:01:57 markh Exp $
|
|
*
|
|
*/
|
|
#include <linux/kernel.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "dgap_types.h"
|
|
#include "dgap_fep5.h"
|
|
#include "dgap_driver.h"
|
|
#include "dgap_conf.h"
|
|
|
|
|
|
/*
|
|
* Function prototypes.
|
|
*/
|
|
static int dgap_gettok(char **in, struct cnode *p);
|
|
static char *dgap_getword(char **in);
|
|
static char *dgap_savestring(char *s);
|
|
static struct cnode *dgap_newnode(int t);
|
|
static int dgap_checknode(struct cnode *p);
|
|
static void dgap_err(char *s);
|
|
|
|
/*
|
|
* Our needed internal static variables...
|
|
*/
|
|
static struct cnode dgap_head;
|
|
#define MAXCWORD 200
|
|
static char dgap_cword[MAXCWORD];
|
|
|
|
struct toklist {
|
|
int token;
|
|
char *string;
|
|
};
|
|
|
|
static struct toklist dgap_tlist[] = {
|
|
{ BEGIN, "config_begin" },
|
|
{ END, "config_end" },
|
|
{ BOARD, "board" },
|
|
{ PCX, "Digi_AccelePort_C/X_PCI" }, /* C/X_PCI */
|
|
{ PEPC, "Digi_AccelePort_EPC/X_PCI" }, /* EPC/X_PCI */
|
|
{ PPCM, "Digi_AccelePort_Xem_PCI" }, /* PCI/Xem */
|
|
{ APORT2_920P, "Digi_AccelePort_2r_920_PCI" },
|
|
{ APORT4_920P, "Digi_AccelePort_4r_920_PCI" },
|
|
{ APORT8_920P, "Digi_AccelePort_8r_920_PCI" },
|
|
{ PAPORT4, "Digi_AccelePort_4r_PCI(EIA-232/RS-422)" },
|
|
{ PAPORT8, "Digi_AccelePort_8r_PCI(EIA-232/RS-422)" },
|
|
{ IO, "io" },
|
|
{ PCIINFO, "pciinfo" },
|
|
{ LINE, "line" },
|
|
{ CONC, "conc" },
|
|
{ CONC, "concentrator" },
|
|
{ CX, "cx" },
|
|
{ CX, "ccon" },
|
|
{ EPC, "epccon" },
|
|
{ EPC, "epc" },
|
|
{ MOD, "module" },
|
|
{ ID, "id" },
|
|
{ STARTO, "start" },
|
|
{ SPEED, "speed" },
|
|
{ CABLE, "cable" },
|
|
{ CONNECT, "connect" },
|
|
{ METHOD, "method" },
|
|
{ STATUS, "status" },
|
|
{ CUSTOM, "Custom" },
|
|
{ BASIC, "Basic" },
|
|
{ MEM, "mem" },
|
|
{ MEM, "memory" },
|
|
{ PORTS, "ports" },
|
|
{ MODEM, "modem" },
|
|
{ NPORTS, "nports" },
|
|
{ TTYN, "ttyname" },
|
|
{ CU, "cuname" },
|
|
{ PRINT, "prname" },
|
|
{ CMAJOR, "major" },
|
|
{ ALTPIN, "altpin" },
|
|
{ USEINTR, "useintr" },
|
|
{ TTSIZ, "ttysize" },
|
|
{ CHSIZ, "chsize" },
|
|
{ BSSIZ, "boardsize" },
|
|
{ UNTSIZ, "schedsize" },
|
|
{ F2SIZ, "f2200size" },
|
|
{ VPSIZ, "vpixsize" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
|
|
/*
|
|
* Parse a configuration file read into memory as a string.
|
|
*/
|
|
int dgap_parsefile(char **in, int Remove)
|
|
{
|
|
struct cnode *p, *brd, *line, *conc;
|
|
int rc;
|
|
char *s = NULL, *s2 = NULL;
|
|
int linecnt = 0;
|
|
|
|
p = &dgap_head;
|
|
brd = line = conc = NULL;
|
|
|
|
/* perhaps we are adding to an existing list? */
|
|
while (p->next != NULL) {
|
|
p = p->next;
|
|
}
|
|
|
|
/* file must start with a BEGIN */
|
|
while ( (rc = dgap_gettok(in,p)) != BEGIN ) {
|
|
if (rc == 0) {
|
|
dgap_err("unexpected EOF");
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
for (; ; ) {
|
|
rc = dgap_gettok(in,p);
|
|
if (rc == 0) {
|
|
dgap_err("unexpected EOF");
|
|
return(-1);
|
|
}
|
|
|
|
switch (rc) {
|
|
case 0:
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
|
|
case BEGIN: /* should only be 1 begin */
|
|
dgap_err("unexpected config_begin\n");
|
|
return(-1);
|
|
|
|
case END:
|
|
return(0);
|
|
|
|
case BOARD: /* board info */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(BNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
|
|
p->u.board.status = dgap_savestring("No");
|
|
line = conc = NULL;
|
|
brd = p;
|
|
linecnt = -1;
|
|
break;
|
|
|
|
case APORT2_920P: /* AccelePort_4 */
|
|
if (p->type != BNODE) {
|
|
dgap_err("unexpected Digi_2r_920 string");
|
|
return(-1);
|
|
}
|
|
p->u.board.type = APORT2_920P;
|
|
p->u.board.v_type = 1;
|
|
DPR_INIT(("Adding Digi_2r_920 PCI to config...\n"));
|
|
break;
|
|
|
|
case APORT4_920P: /* AccelePort_4 */
|
|
if (p->type != BNODE) {
|
|
dgap_err("unexpected Digi_4r_920 string");
|
|
return(-1);
|
|
}
|
|
p->u.board.type = APORT4_920P;
|
|
p->u.board.v_type = 1;
|
|
DPR_INIT(("Adding Digi_4r_920 PCI to config...\n"));
|
|
break;
|
|
|
|
case APORT8_920P: /* AccelePort_8 */
|
|
if (p->type != BNODE) {
|
|
dgap_err("unexpected Digi_8r_920 string");
|
|
return(-1);
|
|
}
|
|
p->u.board.type = APORT8_920P;
|
|
p->u.board.v_type = 1;
|
|
DPR_INIT(("Adding Digi_8r_920 PCI to config...\n"));
|
|
break;
|
|
|
|
case PAPORT4: /* AccelePort_4 PCI */
|
|
if (p->type != BNODE) {
|
|
dgap_err("unexpected Digi_4r(PCI) string");
|
|
return(-1);
|
|
}
|
|
p->u.board.type = PAPORT4;
|
|
p->u.board.v_type = 1;
|
|
DPR_INIT(("Adding Digi_4r PCI to config...\n"));
|
|
break;
|
|
|
|
case PAPORT8: /* AccelePort_8 PCI */
|
|
if (p->type != BNODE) {
|
|
dgap_err("unexpected Digi_8r string");
|
|
return(-1);
|
|
}
|
|
p->u.board.type = PAPORT8;
|
|
p->u.board.v_type = 1;
|
|
DPR_INIT(("Adding Digi_8r PCI to config...\n"));
|
|
break;
|
|
|
|
case PCX: /* PCI C/X */
|
|
if (p->type != BNODE) {
|
|
dgap_err("unexpected Digi_C/X_(PCI) string");
|
|
return(-1);
|
|
}
|
|
p->u.board.type = PCX;
|
|
p->u.board.v_type = 1;
|
|
p->u.board.conc1 = 0;
|
|
p->u.board.conc2 = 0;
|
|
p->u.board.module1 = 0;
|
|
p->u.board.module2 = 0;
|
|
DPR_INIT(("Adding PCI C/X to config...\n"));
|
|
break;
|
|
|
|
case PEPC: /* PCI EPC/X */
|
|
if (p->type != BNODE) {
|
|
dgap_err("unexpected \"Digi_EPC/X_(PCI)\" string");
|
|
return(-1);
|
|
}
|
|
p->u.board.type = PEPC;
|
|
p->u.board.v_type = 1;
|
|
p->u.board.conc1 = 0;
|
|
p->u.board.conc2 = 0;
|
|
p->u.board.module1 = 0;
|
|
p->u.board.module2 = 0;
|
|
DPR_INIT(("Adding PCI EPC/X to config...\n"));
|
|
break;
|
|
|
|
case PPCM: /* PCI/Xem */
|
|
if (p->type != BNODE) {
|
|
dgap_err("unexpected PCI/Xem string");
|
|
return(-1);
|
|
}
|
|
p->u.board.type = PPCM;
|
|
p->u.board.v_type = 1;
|
|
p->u.board.conc1 = 0;
|
|
p->u.board.conc2 = 0;
|
|
DPR_INIT(("Adding PCI XEM to config...\n"));
|
|
break;
|
|
|
|
case IO: /* i/o port */
|
|
if (p->type != BNODE) {
|
|
dgap_err("IO port only vaild for boards");
|
|
return(-1);
|
|
}
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.board.portstr = dgap_savestring(s);
|
|
p->u.board.port = (short)simple_strtol(s, &s2, 0);
|
|
if ((short)strlen(s) > (short)(s2 - s)) {
|
|
dgap_err("bad number for IO port");
|
|
return(-1);
|
|
}
|
|
p->u.board.v_port = 1;
|
|
DPR_INIT(("Adding IO (%s) to config...\n", s));
|
|
break;
|
|
|
|
case MEM: /* memory address */
|
|
if (p->type != BNODE) {
|
|
dgap_err("memory address only vaild for boards");
|
|
return(-1);
|
|
}
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.board.addrstr = dgap_savestring(s);
|
|
p->u.board.addr = simple_strtoul(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for memory address");
|
|
return(-1);
|
|
}
|
|
p->u.board.v_addr = 1;
|
|
DPR_INIT(("Adding MEM (%s) to config...\n", s));
|
|
break;
|
|
|
|
case PCIINFO: /* pci information */
|
|
if (p->type != BNODE) {
|
|
dgap_err("memory address only vaild for boards");
|
|
return(-1);
|
|
}
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.board.pcibusstr = dgap_savestring(s);
|
|
p->u.board.pcibus = simple_strtoul(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for pci bus");
|
|
return(-1);
|
|
}
|
|
p->u.board.v_pcibus = 1;
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.board.pcislotstr = dgap_savestring(s);
|
|
p->u.board.pcislot = simple_strtoul(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for pci slot");
|
|
return(-1);
|
|
}
|
|
p->u.board.v_pcislot = 1;
|
|
|
|
DPR_INIT(("Adding PCIINFO (%s %s) to config...\n", p->u.board.pcibusstr,
|
|
p->u.board.pcislotstr));
|
|
break;
|
|
|
|
case METHOD:
|
|
if (p->type != BNODE) {
|
|
dgap_err("install method only vaild for boards");
|
|
return(-1);
|
|
}
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.board.method = dgap_savestring(s);
|
|
p->u.board.v_method = 1;
|
|
DPR_INIT(("Adding METHOD (%s) to config...\n", s));
|
|
break;
|
|
|
|
case STATUS:
|
|
if (p->type != BNODE) {
|
|
dgap_err("config status only vaild for boards");
|
|
return(-1);
|
|
}
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.board.status = dgap_savestring(s);
|
|
DPR_INIT(("Adding STATUS (%s) to config...\n", s));
|
|
break;
|
|
|
|
case NPORTS: /* number of ports */
|
|
if (p->type == BNODE) {
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.board.nport = (char)simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for number of ports");
|
|
return(-1);
|
|
}
|
|
p->u.board.v_nport = 1;
|
|
} else if (p->type == CNODE) {
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.conc.nport = (char)simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for number of ports");
|
|
return(-1);
|
|
}
|
|
p->u.conc.v_nport = 1;
|
|
} else if (p->type == MNODE) {
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.module.nport = (char)simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for number of ports");
|
|
return(-1);
|
|
}
|
|
p->u.module.v_nport = 1;
|
|
} else {
|
|
dgap_err("nports only valid for concentrators or modules");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding NPORTS (%s) to config...\n", s));
|
|
break;
|
|
|
|
case ID: /* letter ID used in tty name */
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
|
|
p->u.board.status = dgap_savestring(s);
|
|
|
|
if (p->type == CNODE) {
|
|
p->u.conc.id = dgap_savestring(s);
|
|
p->u.conc.v_id = 1;
|
|
} else if (p->type == MNODE) {
|
|
p->u.module.id = dgap_savestring(s);
|
|
p->u.module.v_id = 1;
|
|
} else {
|
|
dgap_err("id only valid for concentrators or modules");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding ID (%s) to config...\n", s));
|
|
break;
|
|
|
|
case STARTO: /* start offset of ID */
|
|
if (p->type == BNODE) {
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.board.start = simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for start of tty count");
|
|
return(-1);
|
|
}
|
|
p->u.board.v_start = 1;
|
|
} else if (p->type == CNODE) {
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.conc.start = simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for start of tty count");
|
|
return(-1);
|
|
}
|
|
p->u.conc.v_start = 1;
|
|
} else if (p->type == MNODE) {
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.module.start = simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for start of tty count");
|
|
return(-1);
|
|
}
|
|
p->u.module.v_start = 1;
|
|
} else {
|
|
dgap_err("start only valid for concentrators or modules");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding START (%s) to config...\n", s));
|
|
break;
|
|
|
|
case TTYN: /* tty name prefix */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(TNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
if ( (s = dgap_getword(in)) == NULL ) {
|
|
dgap_err("unexpeced end of file");
|
|
return(-1);
|
|
}
|
|
if ( (p->u.ttyname = dgap_savestring(s)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding TTY (%s) to config...\n", s));
|
|
break;
|
|
|
|
case CU: /* cu name prefix */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(CUNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
if ( (s = dgap_getword(in)) == NULL ) {
|
|
dgap_err("unexpeced end of file");
|
|
return(-1);
|
|
}
|
|
if ( (p->u.cuname = dgap_savestring(s)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding CU (%s) to config...\n", s));
|
|
break;
|
|
|
|
case LINE: /* line information */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if (brd == NULL) {
|
|
dgap_err("must specify board before line info");
|
|
return(-1);
|
|
}
|
|
switch (brd->u.board.type) {
|
|
case PPCM:
|
|
dgap_err("line not vaild for PC/em");
|
|
return(-1);
|
|
}
|
|
if ( (p->next = dgap_newnode(LNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
conc = NULL;
|
|
line = p;
|
|
linecnt++;
|
|
DPR_INIT(("Adding LINE to config...\n"));
|
|
break;
|
|
|
|
case CONC: /* concentrator information */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if (line == NULL) {
|
|
dgap_err("must specify line info before concentrator");
|
|
return(-1);
|
|
}
|
|
if ( (p->next = dgap_newnode(CNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
conc = p;
|
|
if (linecnt)
|
|
brd->u.board.conc2++;
|
|
else
|
|
brd->u.board.conc1++;
|
|
|
|
DPR_INIT(("Adding CONC to config...\n"));
|
|
break;
|
|
|
|
case CX: /* c/x type concentrator */
|
|
if (p->type != CNODE) {
|
|
dgap_err("cx only valid for concentrators");
|
|
return(-1);
|
|
}
|
|
p->u.conc.type = CX;
|
|
p->u.conc.v_type = 1;
|
|
DPR_INIT(("Adding CX to config...\n"));
|
|
break;
|
|
|
|
case EPC: /* epc type concentrator */
|
|
if (p->type != CNODE) {
|
|
dgap_err("cx only valid for concentrators");
|
|
return(-1);
|
|
}
|
|
p->u.conc.type = EPC;
|
|
p->u.conc.v_type = 1;
|
|
DPR_INIT(("Adding EPC to config...\n"));
|
|
break;
|
|
|
|
case MOD: /* EBI module */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if (brd == NULL) {
|
|
dgap_err("must specify board info before EBI modules");
|
|
return(-1);
|
|
}
|
|
switch (brd->u.board.type) {
|
|
case PPCM:
|
|
linecnt = 0;
|
|
break;
|
|
default:
|
|
if (conc == NULL) {
|
|
dgap_err("must specify concentrator info before EBI module");
|
|
return(-1);
|
|
}
|
|
}
|
|
if ( (p->next = dgap_newnode(MNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
if (linecnt)
|
|
brd->u.board.module2++;
|
|
else
|
|
brd->u.board.module1++;
|
|
|
|
DPR_INIT(("Adding MOD to config...\n"));
|
|
break;
|
|
|
|
case PORTS: /* ports type EBI module */
|
|
if (p->type != MNODE) {
|
|
dgap_err("ports only valid for EBI modules");
|
|
return(-1);
|
|
}
|
|
p->u.module.type = PORTS;
|
|
p->u.module.v_type = 1;
|
|
DPR_INIT(("Adding PORTS to config...\n"));
|
|
break;
|
|
|
|
case MODEM: /* ports type EBI module */
|
|
if (p->type != MNODE) {
|
|
dgap_err("modem only valid for modem modules");
|
|
return(-1);
|
|
}
|
|
p->u.module.type = MODEM;
|
|
p->u.module.v_type = 1;
|
|
DPR_INIT(("Adding MODEM to config...\n"));
|
|
break;
|
|
|
|
case CABLE:
|
|
if (p->type == LNODE) {
|
|
if ((s = dgap_getword(in)) == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.line.cable = dgap_savestring(s);
|
|
p->u.line.v_cable = 1;
|
|
}
|
|
DPR_INIT(("Adding CABLE (%s) to config...\n", s));
|
|
break;
|
|
|
|
case SPEED: /* sync line speed indication */
|
|
if (p->type == LNODE) {
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.line.speed = (char)simple_strtol(s, &s2, 0);
|
|
if ((short)strlen(s) > (short)(s2 - s)) {
|
|
dgap_err("bad number for line speed");
|
|
return(-1);
|
|
}
|
|
p->u.line.v_speed = 1;
|
|
} else if (p->type == CNODE) {
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.conc.speed = (char)simple_strtol(s, &s2, 0);
|
|
if ((short)strlen(s) > (short)(s2 - s)) {
|
|
dgap_err("bad number for line speed");
|
|
return(-1);
|
|
}
|
|
p->u.conc.v_speed = 1;
|
|
} else {
|
|
dgap_err("speed valid only for lines or concentrators.");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding SPEED (%s) to config...\n", s));
|
|
break;
|
|
|
|
case CONNECT:
|
|
if (p->type == CNODE) {
|
|
if ((s = dgap_getword(in)) == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.conc.connect = dgap_savestring(s);
|
|
p->u.conc.v_connect = 1;
|
|
}
|
|
DPR_INIT(("Adding CONNECT (%s) to config...\n", s));
|
|
break;
|
|
case PRINT: /* transparent print name prefix */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(PNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
if ( (s = dgap_getword(in)) == NULL ) {
|
|
dgap_err("unexpeced end of file");
|
|
return(-1);
|
|
}
|
|
if ( (p->u.printname = dgap_savestring(s)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding PRINT (%s) to config...\n", s));
|
|
break;
|
|
|
|
case CMAJOR: /* major number */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(JNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.majornumber = simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for major number");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding CMAJOR (%s) to config...\n", s));
|
|
break;
|
|
|
|
case ALTPIN: /* altpin setting */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(ANODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.altpin = simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for altpin");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding ALTPIN (%s) to config...\n", s));
|
|
break;
|
|
|
|
case USEINTR: /* enable interrupt setting */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(INTRNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.useintr = simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for useintr");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding USEINTR (%s) to config...\n", s));
|
|
break;
|
|
|
|
case TTSIZ: /* size of tty structure */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(TSNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.ttysize = simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for ttysize");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding TTSIZ (%s) to config...\n", s));
|
|
break;
|
|
|
|
case CHSIZ: /* channel structure size */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(CSNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.chsize = simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for chsize");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding CHSIZE (%s) to config...\n", s));
|
|
break;
|
|
|
|
case BSSIZ: /* board structure size */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(BSNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.bssize = simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for bssize");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding BSSIZ (%s) to config...\n", s));
|
|
break;
|
|
|
|
case UNTSIZ: /* sched structure size */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(USNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.unsize = simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for schedsize");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding UNTSIZ (%s) to config...\n", s));
|
|
break;
|
|
|
|
case F2SIZ: /* f2200 structure size */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(FSNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.f2size = simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for f2200size");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding F2SIZ (%s) to config...\n", s));
|
|
break;
|
|
|
|
case VPSIZ: /* vpix structure size */
|
|
if (dgap_checknode(p))
|
|
return(-1);
|
|
if ( (p->next = dgap_newnode(VSNODE)) == NULL ) {
|
|
dgap_err("out of memory");
|
|
return(-1);
|
|
}
|
|
p = p->next;
|
|
s = dgap_getword(in);
|
|
if (s == NULL) {
|
|
dgap_err("unexpected end of file");
|
|
return(-1);
|
|
}
|
|
p->u.vpixsize = simple_strtol(s, &s2, 0);
|
|
if ((int)strlen(s) > (int)(s2 - s)) {
|
|
dgap_err("bad number for vpixsize");
|
|
return(-1);
|
|
}
|
|
DPR_INIT(("Adding VPSIZ (%s) to config...\n", s));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* dgap_sindex: much like index(), but it looks for a match of any character in
|
|
* the group, and returns that position. If the first character is a ^, then
|
|
* this will match the first occurrence not in that group.
|
|
*/
|
|
static char *dgap_sindex (char *string, char *group)
|
|
{
|
|
char *ptr;
|
|
|
|
if (!string || !group)
|
|
return (char *) NULL;
|
|
|
|
if (*group == '^') {
|
|
group++;
|
|
for (; *string; string++) {
|
|
for (ptr = group; *ptr; ptr++) {
|
|
if (*ptr == *string)
|
|
break;
|
|
}
|
|
if (*ptr == '\0')
|
|
return string;
|
|
}
|
|
}
|
|
else {
|
|
for (; *string; string++) {
|
|
for (ptr = group; *ptr; ptr++) {
|
|
if (*ptr == *string)
|
|
return string;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (char *) NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Get a token from the input file; return 0 if end of file is reached
|
|
*/
|
|
static int dgap_gettok(char **in, struct cnode *p)
|
|
{
|
|
char *w;
|
|
struct toklist *t;
|
|
|
|
if (strstr(dgap_cword, "boar")) {
|
|
w = dgap_getword(in);
|
|
snprintf(dgap_cword, MAXCWORD, "%s", w);
|
|
for (t = dgap_tlist; t->token != 0; t++) {
|
|
if ( !strcmp(w, t->string)) {
|
|
return(t->token);
|
|
}
|
|
}
|
|
dgap_err("board !!type not specified");
|
|
return(1);
|
|
}
|
|
else {
|
|
while ( (w = dgap_getword(in)) != NULL ) {
|
|
snprintf(dgap_cword, MAXCWORD, "%s", w);
|
|
for (t = dgap_tlist; t->token != 0; t++) {
|
|
if ( !strcmp(w, t->string) )
|
|
return(t->token);
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* get a word from the input stream, also keep track of current line number.
|
|
* words are separated by whitespace.
|
|
*/
|
|
static char *dgap_getword(char **in)
|
|
{
|
|
char *ret_ptr = *in;
|
|
|
|
char *ptr = dgap_sindex(*in, " \t\n");
|
|
|
|
/* If no word found, return null */
|
|
if (!ptr)
|
|
return NULL;
|
|
|
|
/* Mark new location for our buffer */
|
|
*ptr = '\0';
|
|
*in = ptr + 1;
|
|
|
|
/* Eat any extra spaces/tabs/newlines that might be present */
|
|
while (*in && **in && ((**in == ' ') || (**in == '\t') || (**in == '\n'))) {
|
|
**in = '\0';
|
|
*in = *in + 1;
|
|
}
|
|
|
|
return ret_ptr;
|
|
}
|
|
|
|
|
|
/*
|
|
* print an error message, giving the line number in the file where
|
|
* the error occurred.
|
|
*/
|
|
static void dgap_err(char *s)
|
|
{
|
|
printk("DGAP: parse: %s\n", s);
|
|
}
|
|
|
|
|
|
/*
|
|
* allocate a new configuration node of type t
|
|
*/
|
|
static struct cnode *dgap_newnode(int t)
|
|
{
|
|
struct cnode *n;
|
|
|
|
n = kmalloc(sizeof(struct cnode), GFP_ATOMIC);
|
|
if (n != NULL) {
|
|
memset((char *)n, 0, sizeof(struct cnode));
|
|
n->type = t;
|
|
}
|
|
return(n);
|
|
}
|
|
|
|
|
|
/*
|
|
* dgap_checknode: see if all the necessary info has been supplied for a node
|
|
* before creating the next node.
|
|
*/
|
|
static int dgap_checknode(struct cnode *p)
|
|
{
|
|
switch (p->type) {
|
|
case BNODE:
|
|
if (p->u.board.v_type == 0) {
|
|
dgap_err("board type !not specified");
|
|
return(1);
|
|
}
|
|
|
|
return(0);
|
|
|
|
case LNODE:
|
|
if (p->u.line.v_speed == 0) {
|
|
dgap_err("line speed not specified");
|
|
return(1);
|
|
}
|
|
return(0);
|
|
|
|
case CNODE:
|
|
if (p->u.conc.v_type == 0) {
|
|
dgap_err("concentrator type not specified");
|
|
return(1);
|
|
}
|
|
if (p->u.conc.v_speed == 0) {
|
|
dgap_err("concentrator line speed not specified");
|
|
return(1);
|
|
}
|
|
if (p->u.conc.v_nport == 0) {
|
|
dgap_err("number of ports on concentrator not specified");
|
|
return(1);
|
|
}
|
|
if (p->u.conc.v_id == 0) {
|
|
dgap_err("concentrator id letter not specified");
|
|
return(1);
|
|
}
|
|
return(0);
|
|
|
|
case MNODE:
|
|
if (p->u.module.v_type == 0) {
|
|
dgap_err("EBI module type not specified");
|
|
return(1);
|
|
}
|
|
if (p->u.module.v_nport == 0) {
|
|
dgap_err("number of ports on EBI module not specified");
|
|
return(1);
|
|
}
|
|
if (p->u.module.v_id == 0) {
|
|
dgap_err("EBI module id letter not specified");
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* save a string somewhere
|
|
*/
|
|
static char *dgap_savestring(char *s)
|
|
{
|
|
char *p;
|
|
if ( (p = kmalloc(strlen(s) + 1, GFP_ATOMIC) ) != NULL) {
|
|
strcpy(p, s);
|
|
}
|
|
return(p);
|
|
}
|
|
|
|
|
|
/*
|
|
* Given a board pointer, returns whether we should use interrupts or not.
|
|
*/
|
|
uint dgap_config_get_useintr(struct board_t *bd)
|
|
{
|
|
struct cnode *p = NULL;
|
|
|
|
if (!bd)
|
|
return(0);
|
|
|
|
for (p = bd->bd_config; p; p = p->next) {
|
|
switch (p->type) {
|
|
case INTRNODE:
|
|
/*
|
|
* check for pcxr types.
|
|
*/
|
|
return p->u.useintr;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If not found, then don't turn on interrupts. */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Given a board pointer, returns whether we turn on altpin or not.
|
|
*/
|
|
uint dgap_config_get_altpin(struct board_t *bd)
|
|
{
|
|
struct cnode *p = NULL;
|
|
|
|
if (!bd)
|
|
return(0);
|
|
|
|
for (p = bd->bd_config; p; p = p->next) {
|
|
switch (p->type) {
|
|
case ANODE:
|
|
/*
|
|
* check for pcxr types.
|
|
*/
|
|
return p->u.altpin;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If not found, then don't turn on interrupts. */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Given a specific type of board, if found, detached link and
|
|
* returns the first occurrence in the list.
|
|
*/
|
|
struct cnode *dgap_find_config(int type, int bus, int slot)
|
|
{
|
|
struct cnode *p, *prev = NULL, *prev2 = NULL, *found = NULL;
|
|
|
|
p = &dgap_head;
|
|
|
|
while (p->next != NULL) {
|
|
prev = p;
|
|
p = p->next;
|
|
|
|
if (p->type == BNODE) {
|
|
|
|
if (p->u.board.type == type) {
|
|
|
|
if (p->u.board.v_pcibus && p->u.board.pcibus != bus) {
|
|
DPR(("Found matching board, but wrong bus position. System says bus %d, we want bus %ld\n",
|
|
bus, p->u.board.pcibus));
|
|
continue;
|
|
}
|
|
if (p->u.board.v_pcislot && p->u.board.pcislot != slot) {
|
|
DPR_INIT(("Found matching board, but wrong slot position. System says slot %d, we want slot %ld\n",
|
|
slot, p->u.board.pcislot));
|
|
continue;
|
|
}
|
|
|
|
DPR_INIT(("Matched type in config file\n"));
|
|
|
|
found = p;
|
|
/*
|
|
* Keep walking thru the list till we find the next board.
|
|
*/
|
|
while (p->next != NULL) {
|
|
prev2 = p;
|
|
p = p->next;
|
|
if (p->type == BNODE) {
|
|
|
|
/*
|
|
* Mark the end of our 1 board chain of configs.
|
|
*/
|
|
prev2->next = NULL;
|
|
|
|
/*
|
|
* Link the "next" board to the previous board,
|
|
* effectively "unlinking" our board from the main config.
|
|
*/
|
|
prev->next = p;
|
|
|
|
return found;
|
|
}
|
|
}
|
|
/*
|
|
* It must be the last board in the list.
|
|
*/
|
|
prev->next = NULL;
|
|
return found;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Given a board pointer, walks the config link, counting up
|
|
* all ports user specified should be on the board.
|
|
* (This does NOT mean they are all actually present right now tho)
|
|
*/
|
|
uint dgap_config_get_number_of_ports(struct board_t *bd)
|
|
{
|
|
int count = 0;
|
|
struct cnode *p = NULL;
|
|
|
|
if (!bd)
|
|
return(0);
|
|
|
|
for (p = bd->bd_config; p; p = p->next) {
|
|
|
|
switch (p->type) {
|
|
case BNODE:
|
|
/*
|
|
* check for pcxr types.
|
|
*/
|
|
if (p->u.board.type > EPCFE)
|
|
count += p->u.board.nport;
|
|
break;
|
|
case CNODE:
|
|
count += p->u.conc.nport;
|
|
break;
|
|
case MNODE:
|
|
count += p->u.module.nport;
|
|
break;
|
|
}
|
|
}
|
|
return (count);
|
|
}
|
|
|
|
char *dgap_create_config_string(struct board_t *bd, char *string)
|
|
{
|
|
char *ptr = string;
|
|
struct cnode *p = NULL;
|
|
struct cnode *q = NULL;
|
|
int speed;
|
|
|
|
if (!bd) {
|
|
*ptr = 0xff;
|
|
return string;
|
|
}
|
|
|
|
for (p = bd->bd_config; p; p = p->next) {
|
|
|
|
switch (p->type) {
|
|
case LNODE:
|
|
*ptr = '\0';
|
|
ptr++;
|
|
*ptr = p->u.line.speed;
|
|
ptr++;
|
|
break;
|
|
case CNODE:
|
|
/*
|
|
* Because the EPC/con concentrators can have EM modules
|
|
* hanging off of them, we have to walk ahead in the list
|
|
* and keep adding the number of ports on each EM to the config.
|
|
* UGH!
|
|
*/
|
|
speed = p->u.conc.speed;
|
|
q = p->next;
|
|
if ((q != NULL) && (q->type == MNODE) ) {
|
|
*ptr = (p->u.conc.nport + 0x80);
|
|
ptr++;
|
|
p = q;
|
|
while ((q->next != NULL) && (q->next->type) == MNODE) {
|
|
*ptr = (q->u.module.nport + 0x80);
|
|
ptr++;
|
|
p = q;
|
|
q = q->next;
|
|
}
|
|
*ptr = q->u.module.nport;
|
|
ptr++;
|
|
} else {
|
|
*ptr = p->u.conc.nport;
|
|
ptr++;
|
|
}
|
|
|
|
*ptr = speed;
|
|
ptr++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
*ptr = 0xff;
|
|
return string;
|
|
}
|
|
|
|
|
|
|
|
char *dgap_get_config_letters(struct board_t *bd, char *string)
|
|
{
|
|
int found = FALSE;
|
|
char *ptr = string;
|
|
struct cnode *cptr = NULL;
|
|
int len = 0;
|
|
int left = MAXTTYNAMELEN;
|
|
|
|
if (!bd) {
|
|
return "<NULL>";
|
|
}
|
|
|
|
for (cptr = bd->bd_config; cptr; cptr = cptr->next) {
|
|
|
|
if ((cptr->type == BNODE) &&
|
|
((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) ||
|
|
(cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) ||
|
|
(cptr->u.board.type == PAPORT8))) {
|
|
|
|
found = TRUE;
|
|
}
|
|
|
|
if (cptr->type == TNODE && found == TRUE) {
|
|
char *ptr1;
|
|
if (strstr(cptr->u.ttyname, "tty")) {
|
|
ptr1 = cptr->u.ttyname;
|
|
ptr1 += 3;
|
|
}
|
|
else {
|
|
ptr1 = cptr->u.ttyname;
|
|
}
|
|
if (ptr1) {
|
|
len = snprintf(ptr, left, "%s", ptr1);
|
|
left -= len;
|
|
ptr += len;
|
|
if (left <= 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cptr->type == CNODE) {
|
|
if (cptr->u.conc.id) {
|
|
len = snprintf(ptr, left, "%s", cptr->u.conc.id);
|
|
left -= len;
|
|
ptr += len;
|
|
if (left <= 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cptr->type == MNODE) {
|
|
if (cptr->u.module.id) {
|
|
len = snprintf(ptr, left, "%s", cptr->u.module.id);
|
|
left -= len;
|
|
ptr += len;
|
|
if (left <= 0)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return string;
|
|
}
|