%union { int i; char *cp; struct idlst *idlst; } %token CPU IDENT CONFIG ANY DEVICE UBA MBA NEXUS CSR DRIVE VECTOR OPTIONS %token CONTROLLER PSEUDO_DEVICE FLAGS ID SEMICOLON NUMBER FPNUMBER TRACE %token DISK SLAVE AT HZ TIMEZONE DST MAXUSERS MASTER COMMA MINUS %type <cp> Save_id ID Dev %type <i> NUMBER FPNUMBER %type <idlst> Id_list %{ /* config.y 1.11 81/05/22 */ #include "config.h" #include <stdio.h> struct device cur; struct device *curp = NULL; char *temp_id; %} %% Configuration: Many_specs ; Many_specs: Many_specs Spec | ; Spec: Device_spec SEMICOLON = { newdev(&cur); } | Config_spec SEMICOLON | TRACE SEMICOLON = { do_trace = ! do_trace; } | SEMICOLON | error SEMICOLON ; Config_spec: CPU Save_id = { struct cputype *cp = (struct cputype *)malloc(sizeof (struct cputype)); cp->cpu_name = ns($2); cp->cpu_next = cputype; cputype = cp; free(temp_id); } | OPTIONS Opt_list | IDENT ID { ident = ns($2); } | CONFIG Save_id ID = { mkconf(temp_id, $3); free(temp_id); } | HZ NUMBER = { yyerror("HZ specification obsolete; delete"); hz = 60; } | TIMEZONE NUMBER = { timezone = 60 * $2; check_tz(); } | TIMEZONE NUMBER DST = { timezone = 60 * $2; dst = 1; check_tz(); } | TIMEZONE FPNUMBER = { timezone = $2; check_tz(); } | TIMEZONE FPNUMBER DST = { timezone = $2; dst = 1; check_tz(); } | MINUS TIMEZONE NUMBER = { timezone = -60 * $3; check_tz(); } | MINUS TIMEZONE NUMBER DST = { timezone = -60 * $3; dst = 1; check_tz(); } | MINUS TIMEZONE FPNUMBER = { timezone = -$3; check_tz(); } | MINUS TIMEZONE FPNUMBER DST = { timezone = -$3; dst = 1; check_tz(); } | MAXUSERS NUMBER = { maxusers = $2; } ; Opt_list: Opt_list COMMA Option | Option ; Option: Save_id = { struct opt *op = (struct opt *)malloc(sizeof (struct opt)); op->op_name = ns($1); op->op_next = opt; opt = op; free(temp_id); } ; Save_id: ID = { $$ = temp_id = ns($1); } ; Dev: UBA = { $$ = ns("uba"); } | MBA = { $$ = ns("mba"); } | ID = { $$ = ns($1); } ; Device_spec: DEVICE Dev_name Dev_info Int_spec = { cur.d_type = DEVICE; } | MASTER Dev_name Dev_info Int_spec = { cur.d_type = MASTER; } | DISK Dev_name Dev_info Int_spec = { cur.d_dk = 1; cur.d_type = DEVICE; } | CONTROLLER Dev_name Dev_info Int_spec = { cur.d_type = CONTROLLER; } | PSEUDO_DEVICE Init_dev Dev = { cur.d_name = $3; cur.d_type = PSEUDO_DEVICE; } | PSEUDO_DEVICE Init_dev Dev NUMBER = { cur.d_name = $3; cur.d_type = PSEUDO_DEVICE; cur.d_count = $4; } ; Dev_name: Init_dev Dev NUMBER = { cur.d_name = $2; if (eq($2, "mba")) seen_mba = TRUE; else if (eq($2, "uba")) seen_uba = TRUE; cur.d_unit = $3; } ; Init_dev: = { init_dev(&cur); } ; Dev_info: Con_info Info_list | ; Con_info: AT Dev NUMBER = { if (eq(cur.d_name, "mba") || eq(cur.d_name, "uba")) { sprintf(errbuf, "%s must be connected to a nexus", cur.d_name); yyerror(errbuf); } cur.d_conn = connect($2, $3); } | AT NEXUS NUMBER = { check_nexus(&cur, $3); cur.d_conn = TO_NEXUS; } ; Info_list: Info_list Info | ; Info: CSR NUMBER = { cur.d_addr = $2; } | DRIVE NUMBER = { cur.d_drive = $2; } | SLAVE NUMBER = { if (cur.d_conn != NULL && cur.d_conn != TO_NEXUS && cur.d_conn->d_type == MASTER) cur.d_slave = $2; else yyerror("can't specify slave--not to master"); } | FLAGS NUMBER = { cur.d_flags = $2; } ; Int_spec: VECTOR Id_list = { cur.d_vec = $2; } | ; Id_list: Save_id = { struct idlst *a = (struct idlst *)malloc(sizeof(struct idlst)); a->id = $1; a->id_next = 0; $$ = a; } | Save_id Id_list = { struct idlst *a = (struct idlst *)malloc(sizeof(struct idlst)); a->id = $1; a->id_next = $2; $$ = a; } ; %% yyerror(s) char *s; { fprintf(stderr, "config: %s at line %d\n", s, yyline); } /* * ns: * Return the passed string in a new space */ char * ns(str) register char *str; { register char *cp; cp = malloc(strlen(str)+1); strcpy(cp, str); return cp; } /* * newdev * Add a device to the list */ newdev(dp) register struct device *dp; { register struct device *np; np = (struct device *) malloc(sizeof *np); *np = *dp; if (curp == NULL) dtab = np; else curp->d_next = np; curp = np; } /* * mkconf * Note that a configuration should be made */ mkconf(dev, sysname) char *dev, *sysname; { register struct file_list *fl; fl = (struct file_list *) malloc(sizeof *fl); fl->f_fn = ns(dev); fl->f_needs = ns(sysname); if (confp == NULL) conf_list = fl; else confp->f_next = fl; confp = fl; } /* * Connect: * Find the pointer to connect to the given device and number. * returns NULL if no such device and prints an error message */ struct device *connect(dev, num) register char *dev; register int num; { register struct device *dp; struct device *huhcon(); if (num == QUES) return huhcon(dev); for (dp = dtab; dp != NULL; dp = dp->d_next) if ((num == dp->d_unit) && eq(dev, dp->d_name)) if (dp->d_type != CONTROLLER && dp->d_type != MASTER) { sprintf(errbuf, "%s connected to non-controller", dev); yyerror(errbuf); return NULL; } else return dp; sprintf(errbuf, "%s %d not defined", dev, num); yyerror(errbuf); return NULL; } /* * huhcon * Connect to an unspecific thing */ struct device *huhcon(dev) register char *dev; { register struct device *dp, *dcp; struct device rdev; int oldtype; /* * First make certain that there are some of these to wildcard on */ for (dp = dtab; dp != NULL; dp = dp->d_next) if (eq(dp->d_name, dev)) break; if (dp == NULL) { sprintf(errbuf, "no %s's to wildcard", dev); yyerror(errbuf); return NULL; } oldtype = dp->d_type; dcp = dp->d_conn; /* * Now see if there is already a wildcard entry for this device * (e.g. Search for a "uba ?") */ for (; dp != NULL; dp = dp->d_next) if (eq(dev, dp->d_name) && dp->d_unit == -1) break; /* * If there isn't, make one becuase everything needs to be connected * to something. */ if (dp == NULL) { dp = &rdev; init_dev(dp); dp->d_unit = QUES; dp->d_name = ns(dev); dp->d_type = oldtype; newdev(dp); dp = curp; /* * Connect it to the same thing that other similar things are * connected to, but make sure it is a wildcard unit * (e.g. up connected to sc ?, here we make connect sc? to a uba?) * If other things like this are on the NEXUS or if the aren't * connected to anything, then make the same connection, else * call ourself to connect to another unspecific device. */ if (dcp == TO_NEXUS || dcp == NULL) dp->d_conn = dcp; else dp->d_conn = connect(dcp->d_name, QUES); } return dp; } /* * init_dev: * Set up the fields in the current device to their * default values. */ init_dev(dp) register struct device *dp; { dp->d_name = "OHNO!!!"; dp->d_type = DEVICE; dp->d_conn = NULL; dp->d_vec = NULL; dp->d_addr = dp->d_flags = dp->d_dk = 0; dp->d_slave = dp->d_drive = dp->d_unit = UNKNOWN; dp->d_count = 0; } /* * Check_nexus: * Make certain that this is a reasonable type of thing to put * on the nexus. */ check_nexus(dev, num) register struct device *dev; int num; { if (!eq(dev->d_name, "uba") && !eq(dev->d_name, "mba")) yyerror("only uba's and mba's should be connected to the nexus"); if (num != QUES) yyerror("can't give specific nexus numbers"); } /* * Check the timezone to make certain it is sensible */ check_tz() { if (timezone > 24 * 60) yyerror("timezone is unreasonable"); else hadtz = TRUE; }