diff --git a/src/bin/pcmcia-cs/Jamfile b/src/bin/pcmcia-cs/Jamfile index 19137a0cc9..2be7b06430 100644 --- a/src/bin/pcmcia-cs/Jamfile +++ b/src/bin/pcmcia-cs/Jamfile @@ -4,4 +4,12 @@ StdBinCommands cardctl.c dump_cis.c dump_cisreg.c - : libroot.so ; + : root ; + +BinCommand pack_cis : + pack_cis.c + lex_cis.l + yacc_cis.y + ; + + diff --git a/src/bin/pcmcia-cs/lex_cis.l b/src/bin/pcmcia-cs/lex_cis.l new file mode 100644 index 0000000000..92316aab0f --- /dev/null +++ b/src/bin/pcmcia-cs/lex_cis.l @@ -0,0 +1,234 @@ +/* Special state for handling include files */ +%x src + +%{ +/* + * lex_cis.l 1.15 2001/08/24 12:21:41 + * + * 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 + * . 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. + */ + +#undef src +#include +#include +#include +#include +#define src 1 + +#include +#include + +#include "pack_cis.h" +#include "yacc_cis.h" + +/* For assembling nice error messages */ +int current_lineno; + +static int lex_number(char *); +static int lex_units(char *, int, int); +static int lex_float(char *); +static int lex_string(char *); + +%} + +int [0-9]+ +hex 0x[0-9a-fA-F]+ +flt [0-9]+\.[0-9]* +str \"([^"]|\\.)*\" + +%% + +\n current_lineno++; +[ \t]* /* skip */ ; +[ ]*[#;].* /* skip */ ; + +funcid return FUNCID; +mfc return MFC; +manfid return MANFID; +vers_1 return VERS_1; +checksum return CHECKSUM; + +common_jedec return CJEDEC; +attr_jedec return AJEDEC; + +dev_info return DEV_INFO; +attr_dev_info return ATTR_DEV_INFO; +no_info return NO_INFO; +NULL return lex_number("0"); +ROM return lex_number("1"); +EPROM return lex_number("3"); +EEPROM return lex_number("4"); +FLASH return lex_number("5"); +SRAM return lex_number("6"); +DRAM return lex_number("7"); +fn_specific return lex_number("13"); + +config return CONFIG; +base return BASE; +mask return MASK; +last_index return LAST_INDEX; +\[post\] return POST; +\[rom\] return ROM; + +cftable_entry return CFTABLE; +\[default\] return DEFAULT; +\[bvd\] return BVD; +\[wp\] return WP; +\[rdybsy\] return RDYBSY; +\[mwait\] return MWAIT; +\[audio\] return AUDIO; +\[readonly\] return READONLY; +\[pwrdown\] return PWRDOWN; + +Vcc return VCC; +Vpp1 return VPP1; +Vpp2 return VPP2; +Vnom return VNOM; +Vmin return VMIN; +Vmax return VMAX; +Istatic return ISTATIC; +Iavg return IAVG; +Ipeak return IPEAK; +Idown return IDOWN; + +io return IO; +memory return MEM; +\[8bit\] return BIT8; +\[16bit\] return BIT16; +\[lines return LINES; +\[range\] return RANGE; + +irq return IRQ_NO; +\[level\] return LEVEL; +\[pulse\] return PULSE; +\[shared\] return SHARED; + +timing return TIMING; +wait return WAIT; +ready return READY; +reserved return RESERVED; + +multi_function return lex_number("0"); +memory_card return lex_number("1"); +serial_port return lex_number("2"); +parallel_port return lex_number("3"); +fixed_disk return lex_number("4"); +video_adapter return lex_number("5"); +network_adapter return lex_number("6"); +aims_card return lex_number("7"); +scsi_adapter return lex_number("8"); + +{int} return lex_number(yytext); +{hex} return lex_number(yytext); + +{int}b return lex_units(yytext, 1, SIZE); +{int}kb return lex_units(yytext, 1024, SIZE); +{int}mb return lex_units(yytext, 1024*1024, SIZE); + +{flt}s return lex_units(yytext, 1000000000, TIME); +{flt}ms return lex_units(yytext, 1000000, TIME); +{flt}us return lex_units(yytext, 1000, TIME); +{flt}ns return lex_units(yytext, 1, TIME); +{int}s return lex_units(yytext, 1000000000, TIME); +{int}ms return lex_units(yytext, 1000000, TIME); +{int}us return lex_units(yytext, 1000, TIME); +{int}ns return lex_units(yytext, 1, TIME); + +{flt}V return lex_units(yytext, 100000, VOLTAGE); +{flt}mV return lex_units(yytext, 100, VOLTAGE); +{flt}uV return lex_units(yytext, 0.1, VOLTAGE); +{int}V return lex_units(yytext, 100000, VOLTAGE); +{int}mV return lex_units(yytext, 100, VOLTAGE); +{int}uV return lex_units(yytext, 0.1, VOLTAGE); + +{flt}A return lex_units(yytext, 10000000, CURRENT); +{flt}mA return lex_units(yytext, 10000, CURRENT); +{flt}uA return lex_units(yytext, 10, CURRENT); +{int}A return lex_units(yytext, 10000000, CURRENT); +{int}mA return lex_units(yytext, 10000, CURRENT); +{int}uA return lex_units(yytext, 10, CURRENT); + +{flt} return lex_float(yytext); + +{str} return lex_string(yytext); + +. return yytext[0]; + +%% + +#ifndef yywrap +int yywrap() { return 1; } +#endif + +/*====================================================================== + + Stuff to parse basic data types + +======================================================================*/ + +static int lex_number(char *s) +{ + yylval.num = strtoul(s, NULL, 0); + return NUMBER; +} + +static int lex_float(char *s) +{ + yylval.flt = strtod(s, NULL); + return FLOAT; +} + +static int lex_units(char *s, int scale, int token) +{ + float f; + sscanf(s, "%f", &f); + yylval.num = scale*f + 0.5; + return token; +} + +static int lex_string(char *s) +{ + int n = strlen(s); + yylval.str = malloc(n-1); + strncpy(yylval.str, s+1, n-2); + yylval.str[n-2] = '\0'; + return STRING; +} + +/*====================================================================== + + The main parser entry point + +======================================================================*/ + +void parse_cis(FILE *f) +{ + current_lineno = 1; + yyrestart(f); + yyparse(); + fclose(f); +} + diff --git a/src/bin/pcmcia-cs/pack_cis.8 b/src/bin/pcmcia-cs/pack_cis.8 new file mode 100644 index 0000000000..f15be45bb5 --- /dev/null +++ b/src/bin/pcmcia-cs/pack_cis.8 @@ -0,0 +1,61 @@ +.\" Copyright (C) 1998 David A. Hinds -- dahinds@users.sourceforge.net +.\" pack_cis.8 1.5 2000/06/12 21:24:49 +.\" +.TH PACK_CIS 8 "2000/06/12 21:24:49" "pcmcia-cs" +.SH NAME +pack_cis \- compile PCMCIA Card Information Structures +.SH SYNOPSIS +.B pack_cis +.RB [ "\-o\ "\c +.I outfile\c +] +.I infile +.SH DESCRIPTION +.B Pack_cis +is used to convert a text description of a PCMCIA Card +Information Structure (CIS) to its packed binary representation. It +can parse a reasonably useful subset of the possible output of the +.B dump_cis +utility. The primary use of +.B pack_cis +is to construct replacement CIS files +for cards that have incomplete, inaccurate, or damaged CIS +structures. Thus, the supported tuple types are mostly limited to +things that are important for correctly configuring typical IO cards. +.PP +By default, the packed data is written to standard output. +.SH FORMAT +The best way to get started writing CIS descriptions will be to use +.B dump_cis +to extract the CIS data from a card, and to examine the CIS files +distributed with the PCMCIA source tree in +.IR etc/cis/ . +.PP +The basic structure of a CIS is a list of tuple descriptions. +Anything following a hash mark (``#'') is treated as a comment. +A multifunction CIS can be described with the notation: +.sp +.RS +.nf +[common tuple list] +mfc { + [tuple list for function 0] +}, { + [tuple list for function 1] +} +.RE +.fi +.sp +.SH OPTIONS +.TP +.BI "\-o " outfile +Write the packed tuple data to the specified file. +.SH FILES +.PD 0 +.TP \w'/etc/pcmcia/cis\ \ \ \|\|'u +/etc/pcmcia/cis +Standard location for packed CIS files +.SH AUTHOR +David Hinds \- dahinds@users.sourceforge.net +.SH "SEE ALSO" +dump_cis(8), cardmgr(8), pcmcia(5). diff --git a/src/bin/pcmcia-cs/pack_cis.c b/src/bin/pcmcia-cs/pack_cis.c new file mode 100644 index 0000000000..67ebbba69b --- /dev/null +++ b/src/bin/pcmcia-cs/pack_cis.c @@ -0,0 +1,447 @@ +/*====================================================================== + + A utility to convert a plain text description of a Card + Information Structure into its packed binary representation. + + pack_cis.c 1.20 2002/10/16 16:38:18 + + 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 + . 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. + + Usage: + + pack_cis [-o outfile] [infile] + + [infile] defaults to stdin, and [outfile] defaults to stdout. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pack_cis.h" + +tuple_info_t *cis_root = NULL, *mfc[8] = { NULL }; +int nf = 0; + +/*====================================================================== + + Support routines for packing parts of configuration table entries + +======================================================================*/ + +static u_int mantissa[] = { + 10, 12, 13, 15, 20, 25, 30, 35, + 40, 45, 50, 55, 60, 70, 80, 90 +}; +static int pack_power(cistpl_power_t *pwr, u_char *b) +{ + u_int tmp, i; + u_char m, e, x, *c = b; + *c = pwr->present; c++; + for (i = 0; i < 7; i++) { + if (!(pwr->present & (1<param[i]; + for (e = 1; ((tmp % 10) == 0) || (tmp > 999); e++) + tmp /= 10; + x = m = 0; + if (tmp < 100) { + if (tmp < 10) { tmp *= 10; e--; } + for (m = 0; m < 16; m++) + if (mantissa[m] == tmp) break; + if (m == 16) { tmp *= 10; e--; } + } + if (tmp >= 100) { + e++; + x = (tmp/10) - ((tmp/10) % 10); + for (m = 0; m < 16; m++) + if (mantissa[m] == x) break; + x = (u_char)(tmp - 10*(u_int)x); + } + *c = (m<<3) | e | (x ? 0x80 : 0); c++; + if (x) { *c = x; c++; } + } + return c-b; +} + +static int pack_io(cistpl_io_t *p, u_char *b) +{ + u_char *c = b; + u_int i, j, ml, ma; + *c = p->flags & (CISTPL_IO_8BIT|CISTPL_IO_16BIT); + if ((p->nwin == 1) && (p->win[0].base == 0)) { + for (i = 1, j = 0; i < p->win[0].len; i *= 2, j++) ; + *c |= j; c++; + } else { + for (i = ma = ml = 0; i < p->nwin; i++) { + ma |= p->win[i].base; + ml |= p->win[i].len-1; + } + ma = (ma > 0xffff) ? 3 : ((ma > 0xff) ? 2 : 1); + ml = (ml > 0xffff) ? 3 : ((ml > 0xff) ? 2 : 1); + *c |= 0x80 | (p->flags & CISTPL_IO_LINES_MASK); c++; + *c = (p->nwin-1) | (ma<<4) | (ml<<6); c++; + if (ma == 3) ma++; if (ml == 3) ml++; + for (i = 0; i < p->nwin; i++) { + for (j = 0; j < ma; j++) { + *c = (p->win[i].base >> (8*j)) & 0xff; c++; + } + for (j = 0; j < ml; j++) { + *c = ((p->win[i].len-1) >> (8*j)) & 0xff; c++; + } + } + } + return c-b; +} + +static int pack_mem(cistpl_mem_t *p, u_char *b) +{ + u_char *c = b; + u_int i, j, ml, ma, ha; + for (i = ma = ml = ha = 0; i < p->nwin; i++) { + ma |= p->win[i].card_addr; + ml |= p->win[i].len; + ha |= p->win[i].host_addr; + } + ma = (ma|ha) >> 8; ml >>= 8; + ma = (ma > 0xffff) ? 3 : ((ma > 0xff) ? 2 : 1); + ml = (ml > 0xffff) ? 3 : ((ml > 0xff) ? 2 : 1); + *c = (p->nwin-1) | (ma<<5) | (ml<<3) | (ha ? 0x80 : 0); c++; + for (i = 0; i < p->nwin; i++) { + for (j = 1; j <= ml; j++) { + *c = (p->win[i].len >> (8*j)) & 0xff; c++; + } + for (j = 1; j <= ma; j++) { + *c = (p->win[i].card_addr >> (8*j)) & 0xff; c++; + } + if (ha) + for (j = 1; j <= ma; j++) { + *c = (p->win[i].host_addr >> (8*j)) & 0xff; c++; + } + } + return c-b; +} + +static int pack_irq(cistpl_irq_t *p, u_char *b) +{ + b[0] = p->IRQInfo1; + if (p->IRQInfo1 & IRQ_INFO2_VALID) { + b[1] = p->IRQInfo2 & 0xff; + b[2] = (p->IRQInfo2 >> 8) & 0xff; + return 3; + } + return 1; +} + +static void pack_cftable(cistpl_cftable_entry_t *p, u_char *b) +{ + u_char *c; + b[2] = p->index | 0x80; + if (p->flags & CISTPL_CFTABLE_DEFAULT) + b[2] |= 0x40; + b[3] = 0x01; + b[3] |= (p->flags & CISTPL_CFTABLE_BVDS) ? 0x10 : 0; + b[3] |= (p->flags & CISTPL_CFTABLE_WP) ? 0x20 : 0; + b[3] |= (p->flags & CISTPL_CFTABLE_RDYBSY) ? 0x40 : 0; + b[3] |= (p->flags & CISTPL_CFTABLE_MWAIT) ? 0x80 : 0; + b[4] = 0; + c = b+5; + if (p->vcc.present) { + b[4]++; c += pack_power(&p->vcc, c); + if (p->vpp1.present) { + b[4]++; c += pack_power(&p->vpp1, c); + if (p->vpp2.present) { + b[4]++; c += pack_power(&p->vpp2, c); + } + } + } + if (p->io.nwin > 0) { + b[4] |= 0x08; + c += pack_io(&p->io, c); + } + if (p->irq.IRQInfo1 > 0) { + b[4] |= 0x10; + c += pack_irq(&p->irq, c); + } + if (p->mem.nwin > 0) { + b[4] |= 0x60; + c += pack_mem(&p->mem, c); + } + if (p->flags >> 8) { + b[4] |= 0x80; + *c++ = p->flags >> 8; + } + b[1] = c-b-2; +} + +/*====================================================================== + + Routines for packing device info tuples + +======================================================================*/ + +static int pack_speed(u_int speed, u_char *b) +{ + u_char e, m, *c = b; + switch (speed) { + case 0: *c |= 0; c++; break; + case 250: *c |= 1; c++; break; + case 200: *c |= 2; c++; break; + case 150: *c |= 3; c++; break; + case 100: *c |= 4; c++; break; + default: + *c |= 7; c++; + for (e = 1; speed > 80; e++) + speed /= 10; + for (m = 0; m < 15; m++) + if (mantissa[m] >= speed) break; + *c = ((m+1)<<3) | e; c++; + } + return c-b; +} + +static void pack_device(cistpl_device_t *d, u_char *b) +{ + u_int i, sz; + u_char e, *c = b+2; + for (i = 0; i < d->ndev; i++) { + *c = (d->dev[i].type<<4); + c += pack_speed(d->dev[i].speed, c); + sz = d->dev[i].size/512; + for (e = 0; sz > 32; e++) + sz /= 4; + *c = (e & 7) | ((sz-1) << 3); c++; + } + *c = 0xff; c++; + b[1] = c-b-2; +} + +/*====================================================================== + + For now, I only implement a subset of tuples types, intended to be + enough to handle most IO-oriented cards. + +======================================================================*/ + +static int pack_tuple(tuple_info_t *t, u_char *b) +{ + cisparse_t *p = t->parse; + u_int i, m; + u_char *c; + + *b = t->type; + switch (t->type) { + case CISTPL_DEVICE: + case CISTPL_DEVICE_A: + if (p) { + pack_device(&p->device, b); + } else { + /* Fake null device tuple */ + b[1] = 3; b[2] = 0; b[3] = 0; b[4] = 0xff; + } + break; + case CISTPL_MANFID: + b[1] = 4; + b[2] = p->manfid.manf & 0xff; + b[3] = p->manfid.manf >> 8; + b[4] = p->manfid.card & 0xff; + b[5] = p->manfid.card >> 8; + break; + case CISTPL_FUNCID: + b[1] = 2; + b[2] = p->funcid.func; + b[3] = p->funcid.sysinit; + break; + case CISTPL_JEDEC_C: + case CISTPL_JEDEC_A: + b[1] = 2*p->jedec.nid; + for (i = 0; i < p->jedec.nid; i++) { + b[2*i+1] = p->jedec.id[i].mfr; + b[2*i+2] = p->jedec.id[i].info; + } + break; + case CISTPL_CONFIG: + b[3] = p->config.last_idx; + i = p->config.base; + for (c = b+4, m = 0; (i > 0) || !m; i >>= 8, m++) { + c[m] = i & 0xff; + } + b[2] = m-1; + i = p->config.rmask[0]; + for (c = c+m, m = 0; (i > 0) || !m; i >>= 8, m++) { + c[m] = i & 0xff; + } + b[2] |= ((m-1) << 2); + b[1] = c+m-b-2; + break; + case CISTPL_VERS_1: + b[2] = p->version_1.major; + b[3] = p->version_1.minor; + c = b+4; + for (i = 0; i < p->version_1.ns; i++) { + strcpy((char *)c, p->version_1.str+p->version_1.ofs[i]); + c += strlen((char *)c) + 1; + } + for (; i < 4; i++) { *c = 0; c++; } + *c = 0xff; c++; + b[1] = c-b-2; + break; + case CISTPL_CFTABLE_ENTRY: + pack_cftable(&p->cftable_entry, b); + break; + case CISTPL_LINKTARGET: + b[1] = 3; b[2] = 'C'; b[3] = 'I'; b[4] = 'S'; + break; + case CISTPL_NO_LINK: + case CISTPL_END: + b[1] = 0; + break; + } + return b[1]+2; +} + +/*====================================================================== + + The following routines handle parsing of aggregates of tuples. + pack_chain() is the simplest: just return a string of tuples and + terminate with an END tuple. pack_mfc() is used to tie the + function-specific tuple chains for a multifunction card together + using a LONGLINK_MFC tuple. And pack_cis() handles a complete + CIS, whether it is multifunction or not. + +======================================================================*/ + +static int pack_chain(tuple_info_t *t, u_char *b) +{ + int n = 0; + tuple_info_t end = { CISTPL_END, NULL, NULL }; + while (t) { + n += pack_tuple(t, b+n); + t = t->next; + } + n += pack_tuple(&end, b+n); + return n; +} + +static int pack_mfc(u_int ofs, u_char *b) +{ + u_int i, j, pos; + tuple_info_t target = { CISTPL_LINKTARGET, NULL, NULL }; + + b[0] = CISTPL_LONGLINK_MFC; + b[1] = 5*nf + 1; + b[2] = nf; + b[5*nf+3] = CISTPL_END; + b[5*nf+4] = 0; + /* Leave space for this tuple and the CISTPL_END tuple */ + pos = 5*nf+5; + for (i = 0; i < nf; i++) { + b[3+i*5] = 0; + for (j = 0; j < 4; j++) + b[4+i*5+j] = ((ofs+pos) >> (8*j)) & 0xff; + pos += pack_tuple(&target, b+pos); + pos += pack_chain(mfc[i], b+pos); + } + return ofs+pos; +} + +static int pack_cis(tuple_info_t *t, u_char *b) +{ + int n = 0; + tuple_info_t device = { CISTPL_DEVICE, NULL, NULL }; + tuple_info_t nolink = { CISTPL_NO_LINK, NULL, NULL }; + tuple_info_t end = { CISTPL_END, NULL, NULL }; + if (t->type != CISTPL_DEVICE) + n = pack_tuple(&device, b); + while (t) { + n += pack_tuple(t, b+n); + t = t->next; + } + if (nf > 0) { + n = pack_mfc(n, b+n); + } else { + n += pack_tuple(&nolink, b+n); + n += pack_tuple(&end, b+n); + } + return n; +} + +/*====================================================================*/ + +int main(int argc, char *argv[]) +{ + int optch, errflg = 0; + char *out = NULL; + u_char buf[1024]; + int n; + FILE *f; + + while ((optch = getopt(argc, argv, "o:")) != -1) { + switch (optch) { + case 'o': + out = strdup(optarg); break; + default: + errflg = 1; break; + } + } + if (errflg || (optind < argc-1)) { + fprintf(stderr, "usage: %s [-o outfile] [infile]\n", + argv[0]); + exit(EXIT_FAILURE); + } + if (optind < argc) { + f = fopen(argv[optind], "r"); + if (!f) { + fprintf(stderr, "could not open '%s': %s\n", argv[optind], + strerror(errno)); + return -1; + } + } else + f = stdin; + parse_cis(f); + fclose(f); + n = pack_cis(cis_root, buf); + if (out) { + f = fopen(out, "w"); + if (!f) { + fprintf(stderr, "could not open '%s': %s\n", out, + strerror(errno)); + return -1; + } + } else f = stdout; + fwrite(buf, n, 1, f); + fclose(f); + + return 0; +} diff --git a/src/bin/pcmcia-cs/pack_cis.h b/src/bin/pcmcia-cs/pack_cis.h new file mode 100644 index 0000000000..c212444e88 --- /dev/null +++ b/src/bin/pcmcia-cs/pack_cis.h @@ -0,0 +1,38 @@ +/* + * pack_cis.h 1.7 2001/08/24 12:16:45 + * + * 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 + * . 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. + */ +typedef struct tuple_info_t { + u_char type; + cisparse_t *parse; + struct tuple_info_t *next; +} tuple_info_t; + +extern tuple_info_t *cis_root, *mfc[8]; +extern int nf; + +void parse_cis(FILE *f); diff --git a/src/bin/pcmcia-cs/yacc_cis.y b/src/bin/pcmcia-cs/yacc_cis.y new file mode 100644 index 0000000000..c6188c5a0d --- /dev/null +++ b/src/bin/pcmcia-cs/yacc_cis.y @@ -0,0 +1,418 @@ +%{ +/* + * yacc_cis.y 1.13 2001/08/24 12:21:41 + * + * 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 + * . 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pack_cis.h" + +/* If bison: generate nicer error messages */ +#define YYERROR_VERBOSE 1 + +extern int current_lineno; + +void yyerror(char *msg, ...); +static tuple_info_t *new_tuple(u_char type, cisparse_t *parse); + +%} + +%token STRING NUMBER FLOAT VOLTAGE CURRENT SIZE +%token VERS_1 MANFID FUNCID CONFIG CFTABLE MFC CHECKSUM +%token POST ROM BASE LAST_INDEX CJEDEC AJEDEC +%token DEV_INFO ATTR_DEV_INFO NO_INFO +%token TIME TIMING WAIT READY RESERVED +%token VNOM VMIN VMAX ISTATIC IAVG IPEAK IDOWN +%token VCC VPP1 VPP2 IO MEM +%token DEFAULT BVD WP RDYBSY MWAIT AUDIO READONLY PWRDOWN +%token BIT8 BIT16 LINES RANGE +%token IRQ_NO MASK LEVEL PULSE SHARED + +%union { + char *str; + u_long num; + float flt; + cistpl_power_t pwr; + cisparse_t *parse; + tuple_info_t *tuple; +} + +%type STRING +%type NUMBER SIZE VOLTAGE CURRENT TIME +%type FLOAT +%type pwr pwrlist +%type vers_1 manfid funcid config cftab io mem irq timing +%type dev_info attr_dev_info checksum cjedec ajedec +%type tuple chain cis; +%% + +cis: chain + { cis_root = $1; } + | chain mfc + { cis_root = $1; } + ; + +chain: /* nothing */ + { $$ = NULL; } + | chain tuple + { + if ($1 == NULL) { + $$ = $2; + } else if ($2 == NULL) { + $$ = $1; + } else { + tuple_info_t *tail = $1; + while (tail->next != NULL) tail = tail->next; + tail->next = $2; + $$ = $1; + } + } + ; + +mfc: MFC '{' chain '}' + { mfc[nf++] = $3; } + | mfc ',' '{' chain '}' + { mfc[nf++] = $4; } + ; + +tuple: dev_info + { $$ = new_tuple(CISTPL_DEVICE, $1); } + | attr_dev_info + { $$ = new_tuple(CISTPL_DEVICE_A, $1); } + | vers_1 + { $$ = new_tuple(CISTPL_VERS_1, $1); } + | manfid + { $$ = new_tuple(CISTPL_MANFID, $1); } + | funcid + { $$ = new_tuple(CISTPL_FUNCID, $1); } + | config + { $$ = new_tuple(CISTPL_CONFIG, $1); } + | cftab + { $$ = new_tuple(CISTPL_CFTABLE_ENTRY, $1); } + | checksum + { $$ = NULL; } + | error + { $$ = NULL; } + | cjedec + { $$ = new_tuple(CISTPL_JEDEC_C, $1); } + | ajedec + { $$ = new_tuple(CISTPL_JEDEC_A, $1); } + ; + +dev_info: DEV_INFO + { $$ = calloc(1, sizeof(cisparse_t)); } + | dev_info NUMBER TIME ',' SIZE + { + $$->device.dev[$$->device.ndev].type = $2; + $$->device.dev[$$->device.ndev].speed = $3; + $$->device.dev[$$->device.ndev].size = $5; + $$->device.ndev++; + } + | dev_info NO_INFO + ; + +attr_dev_info: ATTR_DEV_INFO + { $$ = calloc(1, sizeof(cisparse_t)); } + | attr_dev_info NUMBER TIME ',' SIZE + { + $$->device.dev[$$->device.ndev].type = $2; + $$->device.dev[$$->device.ndev].speed = $3; + $$->device.dev[$$->device.ndev].size = $5; + $$->device.ndev++; + } + | attr_dev_info NO_INFO + ; + +vers_1: VERS_1 FLOAT + { + $$ = calloc(1, sizeof(cisparse_t)); + $$->version_1.major = $2; + $2 -= floor($2+0.01); + while (fabs($2 - floor($2+0.5)) > 0.01) { + $2 *= 10; + } + $$->version_1.minor = $2+0.01; + } + | vers_1 ',' STRING + { + cistpl_vers_1_t *v = &$$->version_1; + u_int pos = 0; + if (v->ns) { + pos = v->ofs[v->ns-1]; + pos += strlen(v->str+pos)+1; + } + v->ofs[v->ns] = pos; + strcpy(v->str+pos, $3); + v->ns++; + } + ; + +manfid: MANFID NUMBER ',' NUMBER + { + $$ = calloc(1, sizeof(cisparse_t)); + $$->manfid.manf = $2; + $$->manfid.card = $4; + } + ; + +funcid: FUNCID NUMBER + { + $$ = calloc(1, sizeof(cisparse_t)); + $$->funcid.func = $2; + } + | funcid POST + { $$->funcid.sysinit |= CISTPL_SYSINIT_POST; } + | funcid ROM + { $$->funcid.sysinit |= CISTPL_SYSINIT_ROM; } + ; + +cjedec: CJEDEC NUMBER NUMBER + { + $$ = calloc(1, sizeof(cisparse_t)); + $$->jedec.id[0].mfr = $2; + $$->jedec.id[0].info = $3; + $$->jedec.nid = 1; + } + | cjedec ',' NUMBER NUMBER + { + $$->jedec.id[$$->jedec.nid].mfr = $3; + $$->jedec.id[$$->jedec.nid++].info = $4; + } + ; + +ajedec: AJEDEC NUMBER NUMBER + { + $$ = calloc(1, sizeof(cisparse_t)); + $$->jedec.id[0].mfr = $2; + $$->jedec.id[0].info = $3; + $$->jedec.nid = 1; + } + | ajedec ',' NUMBER NUMBER + { + $$->jedec.id[$$->jedec.nid].mfr = $3; + $$->jedec.id[$$->jedec.nid++].info = $4; + } + ; + +config: CONFIG BASE NUMBER MASK NUMBER LAST_INDEX NUMBER + { + $$ = calloc(1, sizeof(cisparse_t)); + $$->config.base = $3; + $$->config.rmask[0] = $5; + $$->config.last_idx = $7; + } + ; + +pwr: VNOM VOLTAGE + { + $$.present = CISTPL_POWER_VNOM; + $$.param[0] = $2; + } + | VMIN VOLTAGE + { + $$.present = CISTPL_POWER_VMIN; + $$.param[0] = $2; + } + | VMAX VOLTAGE + { + $$.present = CISTPL_POWER_VMAX; + $$.param[0] = $2; + } + | ISTATIC CURRENT + { + $$.present = CISTPL_POWER_ISTATIC; + $$.param[0] = $2; + } + | IAVG CURRENT + { + $$.present = CISTPL_POWER_IAVG; + $$.param[0] = $2; + } + | IPEAK CURRENT + { + $$.present = CISTPL_POWER_IPEAK; + $$.param[0] = $2; + } + | IDOWN CURRENT + { + $$.present = CISTPL_POWER_IDOWN; + $$.param[0] = $2; + } + ; + +pwrlist: /* nothing */ + { + $$.present = 0; + } + | pwrlist pwr + { + $$.present |= 1<<($2.present); + $$.param[$2.present] = $2.param[0]; + } + ; + +timing: cftab TIMING + | timing WAIT TIME + | timing READY TIME + | timing RESERVED TIME + ; + +io: cftab IO NUMBER '-' NUMBER + { + int n = $$->cftable_entry.io.nwin; + $$->cftable_entry.io.win[n].base = $3; + $$->cftable_entry.io.win[n].len = $5-$3+1; + $$->cftable_entry.io.nwin++; + } + | io ',' NUMBER '-' NUMBER + { + int n = $$->cftable_entry.io.nwin; + $$->cftable_entry.io.win[n].base = $3; + $$->cftable_entry.io.win[n].len = $5-$3+1; + $$->cftable_entry.io.nwin++; + } + | io BIT8 + { $$->cftable_entry.io.flags |= CISTPL_IO_8BIT; } + | io BIT16 + { $$->cftable_entry.io.flags |= CISTPL_IO_16BIT; } + | io LINES '=' NUMBER ']' + { $$->cftable_entry.io.flags |= $4; } + | io RANGE + ; + +mem: cftab MEM NUMBER '-' NUMBER '@' NUMBER + { + int n = $$->cftable_entry.mem.nwin; + $$->cftable_entry.mem.win[n].card_addr = $3; + $$->cftable_entry.mem.win[n].host_addr = $7; + $$->cftable_entry.mem.win[n].len = $5-$3+1; + $$->cftable_entry.mem.nwin++; + } + | mem ',' NUMBER '-' NUMBER '@' NUMBER + { + int n = $$->cftable_entry.mem.nwin; + $$->cftable_entry.mem.win[n].card_addr = $3; + $$->cftable_entry.mem.win[n].host_addr = $7; + $$->cftable_entry.mem.win[n].len = $5-$3+1; + $$->cftable_entry.mem.nwin++; + } + | mem BIT8 + { $$->cftable_entry.io.flags |= CISTPL_IO_8BIT; } + | mem BIT16 + { $$->cftable_entry.io.flags |= CISTPL_IO_16BIT; } + ; + +irq: cftab IRQ_NO NUMBER + { $$->cftable_entry.irq.IRQInfo1 = ($3 & 0x0f); } + | cftab IRQ_NO MASK NUMBER + { + $$->cftable_entry.irq.IRQInfo1 = IRQ_INFO2_VALID; + $$->cftable_entry.irq.IRQInfo2 = $4; + } + | irq PULSE + { $$->cftable_entry.irq.IRQInfo1 |= IRQ_PULSE_ID; } + | irq LEVEL + { $$->cftable_entry.irq.IRQInfo1 |= IRQ_LEVEL_ID; } + | irq SHARED + { $$->cftable_entry.irq.IRQInfo1 |= IRQ_SHARE_ID; } + ; + +cftab: CFTABLE NUMBER + { + $$ = calloc(1, sizeof(cisparse_t)); + $$->cftable_entry.index = $2; + } + | cftab DEFAULT + { $$->cftable_entry.flags |= CISTPL_CFTABLE_DEFAULT; } + | cftab BVD + { $$->cftable_entry.flags |= CISTPL_CFTABLE_BVDS; } + | cftab WP + { $$->cftable_entry.flags |= CISTPL_CFTABLE_WP; } + | cftab RDYBSY + { $$->cftable_entry.flags |= CISTPL_CFTABLE_RDYBSY; } + | cftab MWAIT + { $$->cftable_entry.flags |= CISTPL_CFTABLE_MWAIT; } + | cftab AUDIO + { $$->cftable_entry.flags |= CISTPL_CFTABLE_AUDIO; } + | cftab READONLY + { $$->cftable_entry.flags |= CISTPL_CFTABLE_READONLY; } + | cftab PWRDOWN + { $$->cftable_entry.flags |= CISTPL_CFTABLE_PWRDOWN; } + | cftab VCC pwrlist + { $$->cftable_entry.vcc = $3; } + | cftab VPP1 pwrlist + { $$->cftable_entry.vpp1 = $3; } + | cftab VPP2 pwrlist + { $$->cftable_entry.vpp2 = $3; } + | io + | mem + | irq + | timing + ; + +checksum: CHECKSUM NUMBER '-' NUMBER '=' NUMBER + { $$ = NULL; } + +%% + +static tuple_info_t *new_tuple(u_char type, cisparse_t *parse) +{ + tuple_info_t *t = calloc(1, sizeof(tuple_info_t)); + t->type = type; + t->parse = parse; + t->next = NULL; +} + +void yyerror(char *msg, ...) +{ + va_list ap; + char str[256]; + + va_start(ap, msg); + sprintf(str, "error at line %d: ", current_lineno); + vsprintf(str+strlen(str), msg, ap); + fprintf(stderr, "%s\n", str); + va_end(ap); +} + +#ifdef DEBUG +void main(int argc, char *argv[]) +{ + if (argc > 1) + parse_cis(argv[1]); +} +#endif