Setting up repository
[linux-libre-firmware.git] / cis-tools / cistpl.c
1 /*======================================================================
2
3     PCMCIA Card Information Structure parser
4
5     The contents of this file are subject to the Mozilla Public
6     License Version 2.0 (the "License"); you may not use this file
7     except in compliance with the License. You may obtain a copy of
8     the License at http://www.mozilla.org/MPL/
9
10     Software distributed under the License is distributed on an "AS
11     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
12     implied. See the License for the specific language governing
13     rights and limitations under the License.
14
15     The initial developer of the original code is David A. Hinds
16     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
17     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
18
19     Alternatively, the contents of this file may be used under the
20     terms of the GNU General Public License version 2 (the "GPL"), in
21     which case the provisions of the GPL are applicable instead of the
22     above.  If you wish to allow the use of your version of this file
23     only under the terms of the GPL and not to allow others to use
24     your version of this file under the MPL, indicate your decision
25     by deleting the provisions above and replace them with the notice
26     and other provisions required by the GPL.  If you do not delete
27     the provisions above, a recipient may use your version of this
28     file under either the MPL or the GPL.
29     
30 ======================================================================*/
31
32 #include <stddef.h>
33
34 #include <asm/byteorder.h>
35 #define le16_to_cpu __le16_to_cpu
36 #define le32_to_cpu __le32_to_cpu
37
38 #include <pcmcia/cs_types.h>
39 #include <pcmcia/cs.h>
40 #include <pcmcia/bulkmem.h>
41 #include <pcmcia/cistpl.h>
42
43 static const u_char mantissa[] = {
44     10, 12, 13, 15, 20, 25, 30, 35,
45     40, 45, 50, 55, 60, 70, 80, 90
46 };
47
48 static const u_int exponent[] = {
49     1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
50 };
51
52 /* Convert an extended speed byte to a time in nanoseconds */
53 #define SPEED_CVT(v) \
54     (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10)
55 /* Convert a power byte to a current in 0.1 microamps */
56 #define POWER_CVT(v) \
57     (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10)
58 #define POWER_SCALE(v)          (exponent[(v)&7])
59
60 /*======================================================================
61
62     Parsing routines for individual tuples
63     
64 ======================================================================*/
65
66 static int parse_device(tuple_t *tuple, cistpl_device_t *device)
67 {
68     int i;
69     u_char scale;
70     u_char *p, *q;
71
72     p = (u_char *)tuple->TupleData;
73     q = p + tuple->TupleDataLen;
74
75     device->ndev = 0;
76     for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
77         
78         if (*p == 0xff) break;
79         device->dev[i].type = (*p >> 4);
80         device->dev[i].wp = (*p & 0x08) ? 1 : 0;
81         switch (*p & 0x07) {
82         case 0: device->dev[i].speed = 0;   break;
83         case 1: device->dev[i].speed = 250; break;
84         case 2: device->dev[i].speed = 200; break;
85         case 3: device->dev[i].speed = 150; break;
86         case 4: device->dev[i].speed = 100; break;
87         case 7:
88             if (++p == q) return CS_BAD_TUPLE;
89             device->dev[i].speed = SPEED_CVT(*p);
90             while (*p & 0x80)
91                 if (++p == q) return CS_BAD_TUPLE;
92             break;
93         default:
94             return CS_BAD_TUPLE;
95         }
96
97         if (++p == q) return CS_BAD_TUPLE;
98         if (*p == 0xff) break;
99         scale = *p & 7;
100         if (scale == 7) return CS_BAD_TUPLE;
101         device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
102         device->ndev++;
103         if (++p == q) break;
104     }
105     
106     return CS_SUCCESS;
107 }
108
109 /*====================================================================*/
110
111 static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
112 {
113     u_char *p;
114     if (tuple->TupleDataLen < 5)
115         return CS_BAD_TUPLE;
116     p = (u_char *)tuple->TupleData;
117     csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2;
118     csum->len = le16_to_cpu(*(u_short *)(p + 2));
119     csum->sum = *(p+4);
120     return CS_SUCCESS;
121 }
122
123 /*====================================================================*/
124
125 static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
126 {
127     if (tuple->TupleDataLen < 4)
128         return CS_BAD_TUPLE;
129     link->addr = le32_to_cpu(*(u_int *)tuple->TupleData);
130     return CS_SUCCESS;
131 }
132
133 /*====================================================================*/
134
135 static int parse_longlink_mfc(tuple_t *tuple,
136                               cistpl_longlink_mfc_t *link)
137 {
138     u_char *p;
139     int i;
140     
141     p = (u_char *)tuple->TupleData;
142     
143     link->nfn = *p; p++;
144     if (tuple->TupleDataLen <= link->nfn*5)
145         return CS_BAD_TUPLE;
146     for (i = 0; i < link->nfn; i++) {
147         link->fn[i].space = *p; p++;
148         link->fn[i].addr = le32_to_cpu(*(u_int *)p); p += 4;
149     }
150     return CS_SUCCESS;
151 }
152
153 /*====================================================================*/
154
155 static int parse_strings(u_char *p, u_char *q, int max,
156                          char *s, u_char *ofs, u_char *found)
157 {
158     int i, j, ns;
159
160     if (p == q) return CS_BAD_TUPLE;
161     ns = 0; j = 0;
162     for (i = 0; i < max; i++) {
163         if (*p == 0xff) break;
164         ofs[i] = j;
165         ns++;
166         for (;;) {
167             s[j++] = (*p == 0xff) ? '\0' : *p;
168             if ((*p == '\0') || (*p == 0xff)) break;
169             if (++p == q) return CS_BAD_TUPLE;
170         }
171         if ((*p == 0xff) || (++p == q)) break;
172     }
173     if (found) {
174         *found = ns;
175         return CS_SUCCESS;
176     } else {
177         return (ns == max) ? CS_SUCCESS : CS_BAD_TUPLE;
178     }
179 }
180
181 /*====================================================================*/
182
183 static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
184 {
185     u_char *p, *q;
186     
187     p = (u_char *)tuple->TupleData;
188     q = p + tuple->TupleDataLen;
189     
190     vers_1->major = *p; p++;
191     vers_1->minor = *p; p++;
192     if (p >= q) return CS_BAD_TUPLE;
193
194     return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
195                          vers_1->str, vers_1->ofs, &vers_1->ns);
196 }
197
198 /*====================================================================*/
199
200 static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
201 {
202     u_char *p, *q;
203     
204     p = (u_char *)tuple->TupleData;
205     q = p + tuple->TupleDataLen;
206     
207     return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
208                          altstr->str, altstr->ofs, &altstr->ns);
209 }
210
211 /*====================================================================*/
212
213 static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
214 {
215     u_char *p, *q;
216     int nid;
217
218     p = (u_char *)tuple->TupleData;
219     q = p + tuple->TupleDataLen;
220
221     for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
222         if (p > q-2) break;
223         jedec->id[nid].mfr = p[0];
224         jedec->id[nid].info = p[1];
225         p += 2;
226     }
227     jedec->nid = nid;
228     return CS_SUCCESS;
229 }
230
231 /*====================================================================*/
232
233 static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
234 {
235     u_short *p;
236     if (tuple->TupleDataLen < 4)
237         return CS_BAD_TUPLE;
238     p = (u_short *)tuple->TupleData;
239     m->manf = le16_to_cpu(p[0]);
240     m->card = le16_to_cpu(p[1]);
241     return CS_SUCCESS;
242 }
243
244 /*====================================================================*/
245
246 static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
247 {
248     u_char *p;
249     if (tuple->TupleDataLen < 2)
250         return CS_BAD_TUPLE;
251     p = (u_char *)tuple->TupleData;
252     f->func = p[0];
253     f->sysinit = p[1];
254     return CS_SUCCESS;
255 }
256
257 /*====================================================================*/
258
259 static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
260 {
261     u_char *p;
262     int i;
263     if (tuple->TupleDataLen < 1)
264         return CS_BAD_TUPLE;
265     p = (u_char *)tuple->TupleData;
266     f->type = p[0];
267     for (i = 1; i < tuple->TupleDataLen; i++)
268         f->data[i-1] = p[i];
269     return CS_SUCCESS;
270 }
271
272 /*====================================================================*/
273
274 static int parse_config(tuple_t *tuple, cistpl_config_t *config)
275 {
276     int rasz, rmsz, i;
277     u_char *p;
278
279     p = (u_char *)tuple->TupleData;
280     rasz = *p & 0x03;
281     rmsz = (*p & 0x3c) >> 2;
282     if (tuple->TupleDataLen < rasz+rmsz+4)
283         return CS_BAD_TUPLE;
284     config->last_idx = *(++p);
285     p++;
286     config->base = 0;
287     for (i = 0; i <= rasz; i++)
288         config->base += p[i] << (8*i);
289     p += rasz+1;
290     for (i = 0; i < 4; i++)
291         config->rmask[i] = 0;
292     for (i = 0; i <= rmsz; i++)
293         config->rmask[i>>2] += p[i] << (8*(i%4));
294     config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
295     return CS_SUCCESS;
296 }
297
298 /*======================================================================
299
300     The following routines are all used to parse the nightmarish
301     config table entries.
302     
303 ======================================================================*/
304
305 static u_char *parse_power(u_char *p, u_char *q,
306                            cistpl_power_t *pwr)
307 {
308     int i;
309     u_int scale;
310
311     if (p == q) return NULL;
312     pwr->present = *p;
313     pwr->flags = 0;
314     p++;
315     for (i = 0; i < 7; i++)
316         if (pwr->present & (1<<i)) {
317             if (p == q) return NULL;
318             pwr->param[i] = POWER_CVT(*p);
319             scale = POWER_SCALE(*p);
320             while (*p & 0x80) {
321                 if (++p == q) return NULL;
322                 if ((*p & 0x7f) < 100)
323                     pwr->param[i] += (*p & 0x7f) * scale / 100;
324                 else if (*p == 0x7d)
325                     pwr->flags |= CISTPL_POWER_HIGHZ_OK;
326                 else if (*p == 0x7e)
327                     pwr->param[i] = 0;
328                 else if (*p == 0x7f)
329                     pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
330                 else
331                     return NULL;
332             }
333             p++;
334         }
335     return p;
336 }
337
338 /*====================================================================*/
339
340 static u_char *parse_timing(u_char *p, u_char *q,
341                             cistpl_timing_t *timing)
342 {
343     u_char scale;
344
345     if (p == q) return NULL;
346     scale = *p;
347     if ((scale & 3) != 3) {
348         if (++p == q) return NULL;
349         timing->wait = SPEED_CVT(*p);
350         timing->waitscale = exponent[scale & 3];
351     } else
352         timing->wait = 0;
353     scale >>= 2;
354     if ((scale & 7) != 7) {
355         if (++p == q) return NULL;
356         timing->ready = SPEED_CVT(*p);
357         timing->rdyscale = exponent[scale & 7];
358     } else
359         timing->ready = 0;
360     scale >>= 3;
361     if (scale != 7) {
362         if (++p == q) return NULL;
363         timing->reserved = SPEED_CVT(*p);
364         timing->rsvscale = exponent[scale];
365     } else
366         timing->reserved = 0;
367     p++;
368     return p;
369 }
370
371 /*====================================================================*/
372
373 static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
374 {
375     int i, j, bsz, lsz;
376
377     if (p == q) return NULL;
378     io->flags = *p;
379
380     if (!(*p & 0x80)) {
381         io->nwin = 1;
382         io->win[0].base = 0;
383         io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
384         return p+1;
385     }
386     
387     if (++p == q) return NULL;
388     io->nwin = (*p & 0x0f) + 1;
389     bsz = (*p & 0x30) >> 4;
390     if (bsz == 3) bsz++;
391     lsz = (*p & 0xc0) >> 6;
392     if (lsz == 3) lsz++;
393     p++;
394     
395     for (i = 0; i < io->nwin; i++) {
396         io->win[i].base = 0;
397         io->win[i].len = 1;
398         for (j = 0; j < bsz; j++, p++) {
399             if (p == q) return NULL;
400             io->win[i].base += *p << (j*8);
401         }
402         for (j = 0; j < lsz; j++, p++) {
403             if (p == q) return NULL;
404             io->win[i].len += *p << (j*8);
405         }
406     }
407     return p;
408 }
409
410 /*====================================================================*/
411
412 static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
413 {
414     int i, j, asz, lsz, has_ha;
415     u_int len, ca, ha;
416
417     if (p == q) return NULL;
418
419     mem->nwin = (*p & 0x07) + 1;
420     lsz = (*p & 0x18) >> 3;
421     asz = (*p & 0x60) >> 5;
422     has_ha = (*p & 0x80);
423     if (++p == q) return NULL;
424     
425     for (i = 0; i < mem->nwin; i++) {
426         len = ca = ha = 0;
427         for (j = 0; j < lsz; j++, p++) {
428             if (p == q) return NULL;
429             len += *p << (j*8);
430         }
431         for (j = 0; j < asz; j++, p++) {
432             if (p == q) return NULL;
433             ca += *p << (j*8);
434         }
435         if (has_ha)
436             for (j = 0; j < asz; j++, p++) {
437                 if (p == q) return NULL;
438                 ha += *p << (j*8);
439             }
440         mem->win[i].len = len << 8;
441         mem->win[i].card_addr = ca << 8;
442         mem->win[i].host_addr = ha << 8;
443     }
444     return p;
445 }
446
447 /*====================================================================*/
448
449 static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
450 {
451     if (p == q) return NULL;
452     irq->IRQInfo1 = *p; p++;
453     if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
454         if (p+2 > q) return NULL;
455         irq->IRQInfo2 = (p[1]<<8) + p[0];
456         p += 2;
457     }
458     return p;
459 }
460
461 /*====================================================================*/
462
463 static int parse_cftable_entry(tuple_t *tuple,
464                                cistpl_cftable_entry_t *entry)
465 {
466     u_char *p, *q, features;
467
468     p = tuple->TupleData;
469     q = p + tuple->TupleDataLen;
470     entry->index = *p & 0x3f;
471     entry->flags = 0;
472     if (*p & 0x40)
473         entry->flags |= CISTPL_CFTABLE_DEFAULT;
474     if (*p & 0x80) {
475         if (++p == q) return CS_BAD_TUPLE;
476         if (*p & 0x10)
477             entry->flags |= CISTPL_CFTABLE_BVDS;
478         if (*p & 0x20)
479             entry->flags |= CISTPL_CFTABLE_WP;
480         if (*p & 0x40)
481             entry->flags |= CISTPL_CFTABLE_RDYBSY;
482         if (*p & 0x80)
483             entry->flags |= CISTPL_CFTABLE_MWAIT;
484         entry->interface = *p & 0x0f;
485     } else
486         entry->interface = 0;
487
488     /* Process optional features */
489     if (++p == q) return CS_BAD_TUPLE;
490     features = *p; p++;
491
492     /* Power options */
493     if ((features & 3) > 0) {
494         p = parse_power(p, q, &entry->vcc);
495         if (p == NULL) return CS_BAD_TUPLE;
496     } else
497         entry->vcc.present = 0;
498     if ((features & 3) > 1) {
499         p = parse_power(p, q, &entry->vpp1);
500         if (p == NULL) return CS_BAD_TUPLE;
501     } else
502         entry->vpp1.present = 0;
503     if ((features & 3) > 2) {
504         p = parse_power(p, q, &entry->vpp2);
505         if (p == NULL) return CS_BAD_TUPLE;
506     } else
507         entry->vpp2.present = 0;
508
509     /* Timing options */
510     if (features & 0x04) {
511         p = parse_timing(p, q, &entry->timing);
512         if (p == NULL) return CS_BAD_TUPLE;
513     } else {
514         entry->timing.wait = 0;
515         entry->timing.ready = 0;
516         entry->timing.reserved = 0;
517     }
518     
519     /* I/O window options */
520     if (features & 0x08) {
521         p = parse_io(p, q, &entry->io);
522         if (p == NULL) return CS_BAD_TUPLE;
523     } else
524         entry->io.nwin = 0;
525     
526     /* Interrupt options */
527     if (features & 0x10) {
528         p = parse_irq(p, q, &entry->irq);
529         if (p == NULL) return CS_BAD_TUPLE;
530     } else
531         entry->irq.IRQInfo1 = 0;
532
533     switch (features & 0x60) {
534     case 0x00:
535         entry->mem.nwin = 0;
536         break;
537     case 0x20:
538         entry->mem.nwin = 1;
539         entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
540         entry->mem.win[0].card_addr = 0;
541         entry->mem.win[0].host_addr = 0;
542         p += 2;
543         if (p > q) return CS_BAD_TUPLE;
544         break;
545     case 0x40:
546         entry->mem.nwin = 1;
547         entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
548         entry->mem.win[0].card_addr =
549             le16_to_cpu(*(u_short *)(p+2)) << 8;
550         entry->mem.win[0].host_addr = 0;
551         p += 4;
552         if (p > q) return CS_BAD_TUPLE;
553         break;
554     case 0x60:
555         p = parse_mem(p, q, &entry->mem);
556         if (p == NULL) return CS_BAD_TUPLE;
557         break;
558     }
559
560     /* Misc features */
561     if (features & 0x80) {
562         if (p == q) return CS_BAD_TUPLE;
563         entry->flags |= (*p << 8);
564         while (*p & 0x80)
565             if (++p == q) return CS_BAD_TUPLE;
566         p++;
567     }
568
569     entry->subtuples = q-p;
570     
571     return CS_SUCCESS;
572 }
573
574 /*====================================================================*/
575
576 static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar)
577 {
578     u_char *p;
579     if (tuple->TupleDataLen < 6)
580         return CS_BAD_TUPLE;
581     p = (u_char *)tuple->TupleData;
582     bar->attr = *p;
583     p += 2;
584     bar->size = le32_to_cpu(*(u_int *)p);
585     return CS_SUCCESS;
586 }
587
588 static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
589 {
590     u_char *p;
591     
592     p = (u_char *)tuple->TupleData;
593     if ((*p != 3) || (tuple->TupleDataLen < 6))
594         return CS_BAD_TUPLE;
595     config->last_idx = *(++p);
596     p++;
597     config->base = le32_to_cpu(*(u_int *)p);
598     config->subtuples = tuple->TupleDataLen - 6;
599     return CS_SUCCESS;
600 }
601
602 static int parse_cftable_entry_cb(tuple_t *tuple,
603                                   cistpl_cftable_entry_cb_t *entry)
604 {
605     u_char *p, *q, features;
606
607     p = tuple->TupleData;
608     q = p + tuple->TupleDataLen;
609     entry->index = *p & 0x3f;
610     entry->flags = 0;
611     if (*p & 0x40)
612         entry->flags |= CISTPL_CFTABLE_DEFAULT;
613
614     /* Process optional features */
615     if (++p == q) return CS_BAD_TUPLE;
616     features = *p; p++;
617
618     /* Power options */
619     if ((features & 3) > 0) {
620         p = parse_power(p, q, &entry->vcc);
621         if (p == NULL) return CS_BAD_TUPLE;
622     } else
623         entry->vcc.present = 0;
624     if ((features & 3) > 1) {
625         p = parse_power(p, q, &entry->vpp1);
626         if (p == NULL) return CS_BAD_TUPLE;
627     } else
628         entry->vpp1.present = 0;
629     if ((features & 3) > 2) {
630         p = parse_power(p, q, &entry->vpp2);
631         if (p == NULL) return CS_BAD_TUPLE;
632     } else
633         entry->vpp2.present = 0;
634
635     /* I/O window options */
636     if (features & 0x08) {
637         if (p == q) return CS_BAD_TUPLE;
638         entry->io = *p; p++;
639     } else
640         entry->io = 0;
641     
642     /* Interrupt options */
643     if (features & 0x10) {
644         p = parse_irq(p, q, &entry->irq);
645         if (p == NULL) return CS_BAD_TUPLE;
646     } else
647         entry->irq.IRQInfo1 = 0;
648
649     if (features & 0x20) {
650         if (p == q) return CS_BAD_TUPLE;
651         entry->mem = *p; p++;
652     } else
653         entry->mem = 0;
654
655     /* Misc features */
656     if (features & 0x80) {
657         if (p == q) return CS_BAD_TUPLE;
658         entry->flags |= (*p << 8);
659         if (*p & 0x80) {
660             if (++p == q) return CS_BAD_TUPLE;
661             entry->flags |= (*p << 16);
662         }
663         while (*p & 0x80)
664             if (++p == q) return CS_BAD_TUPLE;
665         p++;
666     }
667
668     entry->subtuples = q-p;
669     
670     return CS_SUCCESS;
671 }
672
673 /*====================================================================*/
674
675 static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
676 {
677     u_char *p, *q;
678     int n;
679
680     p = (u_char *)tuple->TupleData;
681     q = p + tuple->TupleDataLen;
682
683     for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
684         if (p > q-6) break;
685         geo->geo[n].buswidth = p[0];
686         geo->geo[n].erase_block = 1 << (p[1]-1);
687         geo->geo[n].read_block  = 1 << (p[2]-1);
688         geo->geo[n].write_block = 1 << (p[3]-1);
689         geo->geo[n].partition   = 1 << (p[4]-1);
690         geo->geo[n].interleave  = 1 << (p[5]-1);
691         p += 6;
692     }
693     geo->ngeo = n;
694     return CS_SUCCESS;
695 }
696
697 /*====================================================================*/
698
699 static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
700 {
701     u_char *p, *q;
702
703     if (tuple->TupleDataLen < 10)
704         return CS_BAD_TUPLE;
705     
706     p = tuple->TupleData;
707     q = p + tuple->TupleDataLen;
708
709     v2->vers = p[0];
710     v2->comply = p[1];
711     v2->dindex = le16_to_cpu(*(u_short *)(p+2));
712     v2->vspec8 = p[6];
713     v2->vspec9 = p[7];
714     v2->nhdr = p[8];
715     p += 9;
716     return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
717 }
718
719 /*====================================================================*/
720
721 static int parse_org(tuple_t *tuple, cistpl_org_t *org)
722 {
723     u_char *p, *q;
724     int i;
725     
726     p = tuple->TupleData;
727     q = p + tuple->TupleDataLen;
728     if (p == q) return CS_BAD_TUPLE;
729     org->data_org = *p;
730     if (++p == q) return CS_BAD_TUPLE;
731     for (i = 0; i < 30; i++) {
732         org->desc[i] = *p;
733         if (*p == '\0') break;
734         if (++p == q) return CS_BAD_TUPLE;
735     }
736     return CS_SUCCESS;
737 }
738
739 /*====================================================================*/
740
741 static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
742 {
743     u_char *p;
744
745     if (tuple->TupleDataLen < 10)
746         return CS_BAD_TUPLE;
747
748     p = tuple->TupleData;
749
750     fmt->type = p[0];
751     fmt->edc = p[1];
752     fmt->offset = le32_to_cpu(*(u_int *)(p+2));
753     fmt->length = le32_to_cpu(*(u_int *)(p+6));
754
755     return CS_SUCCESS;
756 }
757
758 /*====================================================================*/
759
760 int parse_tuple(tuple_t *tuple, cisparse_t *parse)
761 {
762     int ret = CS_SUCCESS;
763     
764     if (tuple->TupleDataLen > tuple->TupleDataMax)
765         return CS_BAD_TUPLE;
766     switch (tuple->TupleCode) {
767     case CISTPL_DEVICE:
768     case CISTPL_DEVICE_A:
769         ret = parse_device(tuple, &parse->device);
770         break;
771     case CISTPL_BAR:
772         ret = parse_bar(tuple, &parse->bar);
773         break;
774     case CISTPL_CONFIG_CB:
775         ret = parse_config_cb(tuple, &parse->config);
776         break;
777     case CISTPL_CFTABLE_ENTRY_CB:
778         ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb);
779         break;
780     case CISTPL_CHECKSUM:
781         ret = parse_checksum(tuple, &parse->checksum);
782         break;
783     case CISTPL_LONGLINK_A:
784     case CISTPL_LONGLINK_C:
785         ret = parse_longlink(tuple, &parse->longlink);
786         break;
787     case CISTPL_LONGLINK_MFC:
788         ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
789         break;
790     case CISTPL_VERS_1:
791         ret = parse_vers_1(tuple, &parse->version_1);
792         break;
793     case CISTPL_ALTSTR:
794         ret = parse_altstr(tuple, &parse->altstr);
795         break;
796     case CISTPL_JEDEC_A:
797     case CISTPL_JEDEC_C:
798         ret = parse_jedec(tuple, &parse->jedec);
799         break;
800     case CISTPL_MANFID:
801         ret = parse_manfid(tuple, &parse->manfid);
802         break;
803     case CISTPL_FUNCID:
804         ret = parse_funcid(tuple, &parse->funcid);
805         break;
806     case CISTPL_FUNCE:
807         ret = parse_funce(tuple, &parse->funce);
808         break;
809     case CISTPL_CONFIG:
810         ret = parse_config(tuple, &parse->config);
811         break;
812     case CISTPL_CFTABLE_ENTRY:
813         ret = parse_cftable_entry(tuple, &parse->cftable_entry);
814         break;
815     case CISTPL_DEVICE_GEO:
816     case CISTPL_DEVICE_GEO_A:
817         ret = parse_device_geo(tuple, &parse->device_geo);
818         break;
819     case CISTPL_VERS_2:
820         ret = parse_vers_2(tuple, &parse->vers_2);
821         break;
822     case CISTPL_ORG:
823         ret = parse_org(tuple, &parse->org);
824         break;
825     case CISTPL_FORMAT:
826     case CISTPL_FORMAT_A:
827         ret = parse_format(tuple, &parse->format);
828         break;
829     case CISTPL_NO_LINK:
830     case CISTPL_LINKTARGET:
831         ret = CS_SUCCESS;
832         break;
833     default:
834         ret = CS_UNSUPPORTED_FUNCTION;
835         break;
836     }
837     return ret;
838 }