554 lines
12 KiB
Plaintext
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
|