propagator/pcmcia/yacc_config.y
2004-01-20 18:32:43 +00:00

554 lines
12 KiB
Plaintext

%{
/*
* yacc_config.y 1.57 2002/08/19 03:19:56
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License
* at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and
* limitations under the License.
*
* 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.
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License version 2 (the "GPL"), in
* which case the provisions of the GPL are applicable instead of the
* above. If you wish to allow the use of your version of this file
* only under the terms of the GPL and not to allow others to use
* your version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the GPL. If you do not delete the
* provisions above, a recipient may use your version of this file
* under either the MPL or the GPL.
*/
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <sys/types.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include "cardmgr.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, ...);
static int add_binding(card_info_t *card, char *name, char *class, int fn);
static int add_module(device_info_t *card, char *name);
%}
%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 device_info_t *device;
struct card_info_t *card;
struct mtd_ident_t *mtd;
struct adjust_list_t *adjust;
}
%type <str> STRING
%type <num> NUMBER
%type <adjust> adjust resource
%type <device> device needs_mtd module class
%type <card> card anonymous tuple manfid pci version function bind cis
%type <mtd> region jedec dtype default mtd
%%
list: /* nothing */
| list adjust
{
adjust_list_t **tail = &root_adjust;
while (*tail != NULL) tail = &(*tail)->next;
*tail = $2;
}
| list device
{
$2->next = root_device;
root_device = $2;
}
| list mtd
{
if ($2->mtd_type == 0) {
yyerror("no ID method for '%s'", $2->name);
YYERROR;
}
if ($2->module == NULL) {
yyerror("no MTD module for '%s'", $2->name);
YYERROR;
}
$2->next = root_mtd;
root_mtd = $2;
}
| list card
{
if ($2->ident_type == 0) {
yyerror("no ID method for '%s'", $2->name);
YYERROR;
}
if ($2->bindings == 0) {
yyerror("no driver bindings for '%s'", $2->name);
YYERROR;
}
if ($2->ident_type == FUNC_IDENT) {
$2->next = root_func;
root_func = $2;
} else {
$2->next = root_card;
root_card = $2;
}
}
| list opts
| list mtd_opts
| list SOURCE
| list error
;
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;
}
;
device: DEVICE STRING
{
$$ = calloc(sizeof(device_info_t), 1);
$$->refs = 1;
strcpy($$->dev_info, $2);
free($2);
}
| needs_mtd
| module
| class
;
card: CARD STRING
{
$$ = calloc(sizeof(card_info_t), 1);
$$->refs = 1;
$$->name = $2;
}
| anonymous
| tuple
| manfid
| pci
| version
| function
| bind
| cis
;
anonymous: card ANONYMOUS
{
if ($1->ident_type) {
yyerror("ID method already defined for '%s'", $1->name);
YYERROR;
}
if (blank_card) {
yyerror("Anonymous card already defined");
YYERROR;
}
$1->ident_type = BLANK_IDENT;
blank_card = $1;
}
;
tuple: card TUPLE NUMBER ',' NUMBER ',' STRING
{
if ($1->ident_type) {
yyerror("ID method already defined for '%s'", $1->name);
YYERROR;
}
$1->ident_type = TUPLE_IDENT;
$1->id.tuple.code = $3;
$1->id.tuple.ofs = $5;
$1->id.tuple.info = $7;
}
;
manfid: card MANFID NUMBER ',' NUMBER
{
if ($1->ident_type & (EXCL_IDENT|MANFID_IDENT)) {
yyerror("ID method already defined for '%s'", $1->name);
YYERROR;
}
$1->ident_type |= MANFID_IDENT;
$1->manfid.manf = $3;
$1->manfid.card = $5;
}
pci: card PCI NUMBER ',' NUMBER
{
if ($1->ident_type) {
yyerror("ID method already defined for '%s'", $1->name);
YYERROR;
}
$1->ident_type = PCI_IDENT;
$1->manfid.manf = $3;
$1->manfid.card = $5;
}
version: card VERSION STRING
{
if ($1->ident_type & (EXCL_IDENT|VERS_1_IDENT)) {
yyerror("ID method already defined for '%s'", $1->name);
YYERROR;
}
$1->ident_type |= VERS_1_IDENT;
$1->id.vers.ns = 1;
$1->id.vers.pi[0] = $3;
}
| version ',' STRING
{
if ($1->id.vers.ns == 4) {
yyerror("too many version strings for '%s'", $1->name);
YYERROR;
}
$1->id.vers.pi[$1->id.vers.ns] = $3;
$1->id.vers.ns++;
}
;
function: card FUNCTION NUMBER
{
if ($1->ident_type) {
yyerror("ID method already defined for '%s'", $1->name);
YYERROR;
}
$1->ident_type = FUNC_IDENT;
$1->id.func.funcid = $3;
}
;
cis: card CIS STRING
{ $1->cis_file = strdup($3); }
;
bind: card BIND STRING
{
if (add_binding($1, $3, NULL, 0) != 0)
YYERROR;
}
| card BIND STRING CLASS STRING
{
if (add_binding($1, $3, $5, 0) != 0)
YYERROR;
}
| card BIND STRING TO NUMBER
{
if (add_binding($1, $3, NULL, $5) != 0)
YYERROR;
}
| card BIND STRING CLASS STRING TO NUMBER
{
if (add_binding($1, $3, $5, $7) != 0)
YYERROR;
}
| bind ',' STRING
{
if (add_binding($1, $3, NULL, 0) != 0)
YYERROR;
}
| bind ',' STRING CLASS STRING
{
if (add_binding($1, $3, $5, 0) != 0)
YYERROR;
}
| bind ',' STRING TO NUMBER
{
if (add_binding($1, $3, NULL, $5) != 0)
YYERROR;
}
| bind ',' STRING CLASS STRING TO NUMBER
{
if (add_binding($1, $3, $5, $7) != 0)
YYERROR;
}
;
needs_mtd: device NEEDS_MTD
{
$1->needs_mtd = 1;
}
;
opts: MODULE STRING OPTS STRING
{
device_info_t *d;
int i, found = 0;
for (d = root_device; d; d = d->next) {
for (i = 0; i < d->modules; i++)
if (strcmp($2, d->module[i]) == 0) break;
if (i < d->modules) {
if (d->opts[i])
free(d->opts[i]);
d->opts[i] = strdup($4);
found = 1;
}
}
free($2); free($4);
if (!found) {
yyerror("module name '%s' not found", $2);
YYERROR;
}
}
;
module: device MODULE STRING
{
if (add_module($1, $3) != 0)
YYERROR;
}
| module OPTS STRING
{
if ($1->opts[$1->modules-1] == NULL) {
$1->opts[$1->modules-1] = $3;
} else {
yyerror("too many module options for '%s'",
$1->module[$1->modules-1]);
YYERROR;
}
}
| module ',' STRING
{
if (add_module($1, $3) != 0)
YYERROR;
}
;
class: device CLASS STRING
{
if ($1->class != NULL) {
yyerror("extra class string '%s'", $3);
YYERROR;
}
$1->class = $3;
}
;
region: REGION STRING
{
$$ = calloc(sizeof(mtd_ident_t), 1);
$$->refs = 1;
$$->name = $2;
}
| dtype
| jedec
| default
;
dtype: region DTYPE NUMBER
{
if ($1->mtd_type) {
yyerror("ID method already defined for '%s'", $1->name);
YYERROR;
}
$1->mtd_type = DTYPE_MTD;
$1->dtype = $3;
}
;
jedec: region JEDEC NUMBER NUMBER
{
if ($1->mtd_type) {
yyerror("ID method already defined for '%s'", $1->name);
YYERROR;
}
$1->mtd_type = JEDEC_MTD;
$1->jedec_mfr = $3;
$1->jedec_info = $4;
}
;
default: region DEFAULT
{
if ($1->mtd_type) {
yyerror("ID method already defined for '%s'", $1->name);
YYERROR;
}
if (default_mtd) {
yyerror("Default MTD already defined");
YYERROR;
}
$1->mtd_type = DEFAULT_MTD;
default_mtd = $1;
}
;
mtd: region MTD STRING
{
if ($1->module != NULL) {
yyerror("extra MTD entry for '%s'", $1->name);
YYERROR;
}
$1->module = $3;
}
| mtd OPTS STRING
{
if ($1->opts == NULL) {
$1->opts = $3;
} else {
yyerror("too many module options for '%s'", $1->module);
YYERROR;
}
}
;
mtd_opts: MTD STRING OPTS STRING
{
mtd_ident_t *m;
int found = 0;
for (m = root_mtd; m; m = m->next)
if (strcmp($2, m->module) == 0) break;
if (m) {
if (m->opts) free(m->opts);
m->opts = strdup($4);
found = 1;
}
free($2); free($4);
if (!found) {
yyerror("MTD name '%s' not found", $2);
YYERROR;
}
}
;
%%
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);
}
static int add_binding(card_info_t *card, char *name, char *class, int fn)
{
device_info_t *dev = root_device;
if (card->bindings == MAX_BINDINGS) {
yyerror("too many bindings\n");
return -1;
}
for (; dev; dev = dev->next)
if (strcmp((char *)dev->dev_info, name) == 0) break;
if (dev == NULL) {
yyerror("unknown device '%s'", name);
return -1;
}
card->device[card->bindings] = dev;
card->dev_fn[card->bindings] = fn;
if (class)
card->class[card->bindings] = strdup(class);
card->bindings++;
free(name);
return 0;
}
static int add_module(device_info_t *dev, char *name)
{
if (dev->modules == MAX_MODULES) {
yyerror("too many modules for '%s'", dev->dev_info);
return -1;
}
dev->module[dev->modules] = name;
dev->opts[dev->modules] = NULL;
dev->modules++;
return 0;
}
#if YYDEBUG
adjust_list_t *root_adjust = NULL;
device_info_t *root_device = NULL;
card_info_t *root_card = NULL, *blank_card = NULL, *root_func = NULL;
mtd_ident_t *root_mtd = NULL, *default_mtd = NULL;
void main(int argc, char *argv[])
{
yydebug = 1;
if (argc > 1)
parse_configfile(argv[1]);
}
#endif