%{
/*
 * Startup tool for non statically mapped PCMCIA sockets - config file parsing
 *
 * (C) 2005		Dominik Brodowski <linux@brodo.de>
 *
 *  The initial developer of the original code is David A. Hinds
 *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
 *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 *
 * License: GPL v2
 */

#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <sys/types.h>

#include "startup.h"

/* If bison: generate nicer error messages */
#define YYERROR_VERBOSE 1

/* from lex_config, for nice error messages */
extern char *current_file;
extern int current_lineno;

void yyerror(char *msg, ...);
int yylex(void);

%}

%token DEVICE CARD ANONYMOUS TUPLE MANFID VERSION FUNCTION PCI
%token BIND CIS TO NEEDS_MTD MODULE OPTS CLASS
%token REGION JEDEC DTYPE DEFAULT MTD
%token INCLUDE EXCLUDE RESERVE IRQ_NO PORT MEMORY
%token STRING NUMBER SOURCE

%union {
    char *str;
    u_long num;
    struct adjust_list_t *adjust;
}

%type <str> STRING
%type <num> NUMBER
%type <adjust> adjust resource
%%
list:	  /* nothing */
	| list adjust
		{
		    adjust_list_t **tail = &root_adjust;
		    while (*tail != NULL) tail = &(*tail)->next;
		    *tail = $2;
		}
	;

adjust:   INCLUDE resource
		{
		    $2->adj.Action = ADD_MANAGED_RESOURCE;
		    $$ = $2;
		}
	| EXCLUDE resource
		{
		    $2->adj.Action = REMOVE_MANAGED_RESOURCE;
		    $$ = $2;
		}
	| RESERVE resource
		{
		    $2->adj.Action = ADD_MANAGED_RESOURCE;
		    $2->adj.Attributes |= RES_RESERVED;
		    $$ = $2;
		}
	| adjust ',' resource
		{
		    $3->adj.Action = $1->adj.Action;
		    $3->adj.Attributes = $1->adj.Attributes;
		    $3->next = $1;
		    $$ = $3;
		}
	;

resource: IRQ_NO NUMBER
		{
		    $$ = calloc(sizeof(adjust_list_t), 1);
		    $$->adj.Resource = RES_IRQ;
		    $$->adj.resource.irq.IRQ = $2;
		}
	| PORT NUMBER '-' NUMBER
		{
		    if (($4 < $2) || ($4 > 0xffff)) {
			yyerror("invalid port range 0x%x-0x%x", $2, $4);
			YYERROR;
		    }
		    $$ = calloc(sizeof(adjust_list_t), 1);
		    $$->adj.Resource = RES_IO_RANGE;
		    $$->adj.resource.io.BasePort = $2;
		    $$->adj.resource.io.NumPorts = $4 - $2 + 1;
		}
	| MEMORY NUMBER '-' NUMBER
		{
		    if ($4 < $2) {
			yyerror("invalid address range 0x%x-0x%x", $2, $4);
			YYERROR;
		    }
		    $$ = calloc(sizeof(adjust_list_t), 1);
		    $$->adj.Resource = RES_MEMORY_RANGE;
		    $$->adj.resource.memory.Base = $2;
		    $$->adj.resource.memory.Size = $4 - $2 + 1;
		}
	;

%%
void yyerror(char *msg, ...)
{
     va_list ap;
     char str[256];

     va_start(ap, msg);
     sprintf(str, "error in file '%s' line %d: ",
	     current_file, current_lineno);
     vsprintf(str+strlen(str), msg, ap);
#if YYDEBUG
     fprintf(stderr, "%s\n", str);
#else
     syslog(LOG_ERR, "%s", str);
#endif
     va_end(ap);
}

