| %{ |
| /* |
| * 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 <sys/types.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdarg.h> |
| #include <math.h> |
| |
| #include <pcmcia/cs_types.h> |
| #include <pcmcia/cs.h> |
| #include <pcmcia/cistpl.h> |
| |
| #include "pack_cis.h" |
| |
| /* If bison: generate nicer error messages */ |
| #define YYERROR_VERBOSE 1 |
| |
| extern int current_lineno; |
| |
| void yyerror(const 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 <str> STRING |
| %type <num> NUMBER SIZE VOLTAGE CURRENT TIME |
| %type <flt> FLOAT |
| %type <pwr> pwr pwrlist |
| %type <parse> vers_1 manfid funcid config cftab io mem irq timing |
| %type <parse> dev_info attr_dev_info checksum cjedec ajedec |
| %type <tuple> 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; |
| return t; |
| } |
| |
| void yyerror(const 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 |