carl9170: Update based on commit cd76b7b483731dc5cb467c28cc70478179fbffd5 dated Feb...
[linux-libre-firmware.git] / cis-tools / pack_cis.c
1 /*======================================================================
2
3     A utility to convert a plain text description of a Card
4     Information Structure into its packed binary representation.
5
6     pack_cis.c 1.20 2002/10/16 16:38:18
7
8     The contents of this file are subject to the Mozilla Public
9     License Version 2.0 (the "License"); you may not use this file
10     except in compliance with the License. You may obtain a copy of
11     the License at http://www.mozilla.org/MPL/
12
13     Software distributed under the License is distributed on an "AS
14     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
15     implied. See the License for the specific language governing
16     rights and limitations under the License.
17
18     The initial developer of the original code is David A. Hinds
19     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
20     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
21
22     Alternatively, the contents of this file may be used under the
23     terms of the GNU General Public License version 2 (the "GPL"), in
24     which case the provisions of the GPL are applicable instead of the
25     above.  If you wish to allow the use of your version of this file
26     only under the terms of the GPL and not to allow others to use
27     your version of this file under the MPL, indicate your decision
28     by deleting the provisions above and replace them with the notice
29     and other provisions required by the GPL.  If you do not delete
30     the provisions above, a recipient may use your version of this
31     file under either the MPL or the GPL.
32
33     Usage:
34
35     pack_cis [-o outfile] [infile]
36
37     [infile] defaults to stdin, and [outfile] defaults to stdout.
38     
39 ======================================================================*/
40
41 #include <sys/types.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <getopt.h>
46 #include <errno.h>
47
48 #include <pcmcia/cs_types.h>
49 #include <pcmcia/cs.h>
50 #include <pcmcia/cistpl.h>
51
52 #include "pack_cis.h"
53
54 tuple_info_t *cis_root = NULL, *mfc[8] = { NULL };
55 u_int nf = 0;
56
57 /*======================================================================
58
59     Support routines for packing parts of configuration table entries
60     
61 ======================================================================*/
62
63 static u_int mantissa[] = {
64     10, 12, 13, 15, 20, 25, 30, 35,
65     40, 45, 50, 55, 60, 70, 80, 90
66 };
67 static int pack_power(cistpl_power_t *pwr, u_char *b)
68 {
69     u_int tmp, i;
70     u_char m, e, x, *c = b;
71     *c = pwr->present; c++;
72     for (i = 0; i < 7; i++) {
73         if (!(pwr->present & (1<<i)))
74             continue;
75         tmp = pwr->param[i];
76         for (e = 1; ((tmp % 10) == 0) || (tmp > 999); e++)
77             tmp /= 10;
78         x = m = 0;
79         if (tmp < 100) {
80             if (tmp < 10) { tmp *= 10; e--; }
81             for (m = 0; m < 16; m++)
82                 if (mantissa[m] == tmp) break;
83             if (m == 16) { tmp *= 10; e--; }
84         }
85         if (tmp >= 100) {
86             e++;
87             x = (tmp/10) - ((tmp/10) % 10);
88             for (m = 0; m < 16; m++)
89                 if (mantissa[m] == x) break;
90             x = (u_char)(tmp - 10*(u_int)x);
91         }
92         *c = (m<<3) | e | (x ? 0x80 : 0); c++;
93         if (x) { *c = x; c++; }
94     }
95     return c-b;
96 }
97
98 static int pack_io(cistpl_io_t *p, u_char *b)
99 {
100     u_char *c = b;
101     u_int i, j, ml, ma;
102     *c = p->flags & (CISTPL_IO_8BIT|CISTPL_IO_16BIT);
103     if ((p->nwin == 1) && (p->win[0].base == 0)) {
104         for (i = 1, j = 0; i < p->win[0].len; i *= 2, j++) ;
105         *c |= j; c++;
106     } else {
107         for (i = ma = ml = 0; i < p->nwin; i++) {
108             ma |= p->win[i].base;
109             ml |= p->win[i].len-1;
110         }
111         ma = (ma > 0xffff) ? 3 : ((ma > 0xff) ? 2 : 1);
112         ml = (ml > 0xffff) ? 3 : ((ml > 0xff) ? 2 : 1);
113         *c |= 0x80 | (p->flags & CISTPL_IO_LINES_MASK); c++;
114         *c = (p->nwin-1) | (ma<<4) | (ml<<6); c++;
115         if (ma == 3) ma++; if (ml == 3) ml++;
116         for (i = 0; i < p->nwin; i++) {
117             for (j = 0; j < ma; j++) {
118                 *c = (p->win[i].base >> (8*j)) & 0xff; c++;
119             }
120             for (j = 0; j < ml; j++) {
121                 *c = ((p->win[i].len-1) >> (8*j)) & 0xff; c++;
122             }
123         }
124     }
125     return c-b;
126 }
127
128 static int pack_mem(cistpl_mem_t *p, u_char *b)
129 {
130     u_char *c = b;
131     u_int i, j, ml, ma, ha;
132     for (i = ma = ml = ha = 0; i < p->nwin; i++) {
133         ma |= p->win[i].card_addr;
134         ml |= p->win[i].len;
135         ha |= p->win[i].host_addr;
136     }
137     ma = (ma|ha) >> 8; ml >>= 8;
138     ma = (ma > 0xffff) ? 3 : ((ma > 0xff) ? 2 : 1);
139     ml = (ml > 0xffff) ? 3 : ((ml > 0xff) ? 2 : 1);
140     *c = (p->nwin-1) | (ma<<5) | (ml<<3) | (ha ? 0x80 : 0); c++;
141     for (i = 0; i < p->nwin; i++) {
142         for (j = 1; j <= ml; j++) {
143             *c = (p->win[i].len >> (8*j)) & 0xff; c++;
144         }
145         for (j = 1; j <= ma; j++) {
146             *c = (p->win[i].card_addr >> (8*j)) & 0xff; c++;
147         }
148         if (ha)
149             for (j = 1; j <= ma; j++) {
150                 *c = (p->win[i].host_addr >> (8*j)) & 0xff; c++;
151             }
152     }
153     return c-b;
154 }
155
156 static int pack_irq(cistpl_irq_t *p, u_char *b)
157 {
158     b[0] = p->IRQInfo1;
159     if (p->IRQInfo1 & IRQ_INFO2_VALID) {
160         b[1] = p->IRQInfo2 & 0xff;
161         b[2] = (p->IRQInfo2 >> 8) & 0xff;
162         return 3;
163     }
164     return 1;
165 }
166
167 static void pack_cftable(cistpl_cftable_entry_t *p, u_char *b)
168 {
169     u_char *c;
170     b[2] = p->index | 0x80;
171     if (p->flags & CISTPL_CFTABLE_DEFAULT)
172         b[2] |= 0x40;
173     b[3] = 0x01;
174     b[3] |= (p->flags & CISTPL_CFTABLE_BVDS) ? 0x10 : 0;
175     b[3] |= (p->flags & CISTPL_CFTABLE_WP) ? 0x20 : 0;
176     b[3] |= (p->flags & CISTPL_CFTABLE_RDYBSY) ? 0x40 : 0;
177     b[3] |= (p->flags & CISTPL_CFTABLE_MWAIT) ? 0x80 : 0;
178     b[4] = 0;
179     c = b+5;
180     if (p->vcc.present) {
181         b[4]++; c += pack_power(&p->vcc, c);
182         if (p->vpp1.present) {
183             b[4]++; c += pack_power(&p->vpp1, c);
184             if (p->vpp2.present) {
185                 b[4]++; c += pack_power(&p->vpp2, c);
186             }
187         }
188     }
189     if (p->io.nwin > 0) {
190         b[4] |= 0x08;
191         c += pack_io(&p->io, c);
192     }
193     if (p->irq.IRQInfo1 > 0) {
194         b[4] |= 0x10;
195         c += pack_irq(&p->irq, c);
196     }
197     if (p->mem.nwin > 0) {
198         b[4] |= 0x60;
199         c += pack_mem(&p->mem, c);
200     }
201     if (p->flags >> 8) {
202         b[4] |= 0x80;
203         *c++ = p->flags >> 8;
204     }
205     b[1] = c-b-2;
206 }
207
208 /*======================================================================
209
210     Routines for packing device info tuples
211     
212 ======================================================================*/
213
214 static int pack_speed(u_int speed, u_char *b)
215 {
216     u_char e, m, *c = b;
217     switch (speed) {
218     case 0:     *c |= 0; c++; break;
219     case 250:   *c |= 1; c++; break;
220     case 200:   *c |= 2; c++; break;
221     case 150:   *c |= 3; c++; break;
222     case 100:   *c |= 4; c++; break;
223     default:
224         *c |= 7; c++;
225         for (e = 1; speed > 80; e++)
226             speed /= 10;
227         for (m = 0; m < 15; m++)
228             if (mantissa[m] >= speed) break;
229         *c = ((m+1)<<3) | e; c++;
230     }
231     return c-b;
232 }
233
234 static void pack_device(cistpl_device_t *d, u_char *b)
235 {
236     u_int i, sz;
237     u_char e, *c = b+2;
238     for (i = 0; i < d->ndev; i++) {
239         *c = (d->dev[i].type<<4);
240         c += pack_speed(d->dev[i].speed, c);
241         sz = d->dev[i].size/512;
242         for (e = 0; sz > 32; e++)
243             sz /= 4;
244         *c = (e & 7) | ((sz-1) << 3); c++;
245     }
246     *c = 0xff; c++;
247     b[1] = c-b-2;
248 }
249
250 /*======================================================================
251
252     For now, I only implement a subset of tuples types, intended to be
253     enough to handle most IO-oriented cards.
254     
255 ======================================================================*/
256
257 static int pack_tuple(tuple_info_t *t, u_char *b)
258 {
259     cisparse_t *p = t->parse;
260     u_int i, m;
261     u_char *c;
262
263     *b = t->type;
264     switch (t->type) {
265     case CISTPL_DEVICE:
266     case CISTPL_DEVICE_A:
267         if (p) {
268             pack_device(&p->device, b);
269         } else {
270             /* Fake null device tuple */
271             b[1] = 3; b[2] = 0; b[3] = 0; b[4] = 0xff;
272         }
273         break;
274     case CISTPL_MANFID:
275         b[1] = 4;
276         b[2] = p->manfid.manf & 0xff;
277         b[3] = p->manfid.manf >> 8;
278         b[4] = p->manfid.card & 0xff;
279         b[5] = p->manfid.card >> 8;
280         break;
281     case CISTPL_FUNCID:
282         b[1] = 2;
283         b[2] = p->funcid.func;
284         b[3] = p->funcid.sysinit;
285         break;
286     case CISTPL_JEDEC_C:
287     case CISTPL_JEDEC_A:
288         b[1] = 2*p->jedec.nid;
289         for (i = 0; i < p->jedec.nid; i++) {
290             b[2*i+1] = p->jedec.id[i].mfr;
291             b[2*i+2] = p->jedec.id[i].info;
292         }
293         break;
294     case CISTPL_CONFIG:
295         b[3] = p->config.last_idx;
296         i = p->config.base;
297         for (c = b+4, m = 0; (i > 0) || !m; i >>= 8, m++) {
298             c[m] = i & 0xff;
299         }
300         b[2] = m-1;
301         i = p->config.rmask[0];
302         for (c = c+m, m = 0; (i > 0) || !m; i >>= 8, m++) {
303             c[m] = i & 0xff;
304         }
305         b[2] |= ((m-1) << 2);
306         b[1] = c+m-b-2;
307         break;
308     case CISTPL_VERS_1:
309         b[2] = p->version_1.major;
310         b[3] = p->version_1.minor;
311         c = b+4;
312         for (i = 0; i < p->version_1.ns; i++) {
313             strcpy((char *)c, p->version_1.str+p->version_1.ofs[i]);
314             c += strlen((char *)c) + 1;
315         }
316         for (; i < 4; i++) { *c = 0; c++; }
317         *c = 0xff; c++;
318         b[1] = c-b-2;
319         break;
320     case CISTPL_CFTABLE_ENTRY:
321         pack_cftable(&p->cftable_entry, b);
322         break;
323     case CISTPL_LINKTARGET:
324         b[1] = 3; b[2] = 'C'; b[3] = 'I'; b[4] = 'S';
325         break;
326     case CISTPL_NO_LINK:
327     case CISTPL_END:
328         b[1] = 0;
329         break;
330     }
331     return b[1]+2;
332 }
333
334 /*======================================================================
335
336     The following routines handle parsing of aggregates of tuples.
337     pack_chain() is the simplest: just return a string of tuples and
338     terminate with an END tuple.  pack_mfc() is used to tie the
339     function-specific tuple chains for a multifunction card together
340     using a LONGLINK_MFC tuple.  And pack_cis() handles a complete
341     CIS, whether it is multifunction or not.
342     
343 ======================================================================*/
344
345 static int pack_chain(tuple_info_t *t, u_char *b)
346 {
347     int n = 0;
348     tuple_info_t end = { CISTPL_END, NULL, NULL };
349     while (t) {
350         n += pack_tuple(t, b+n);
351         t = t->next;
352     }
353     n += pack_tuple(&end, b+n);
354     return n;
355 }
356
357 static int pack_mfc(u_int ofs, u_char *b)
358 {
359     u_int i, j, pos;
360     tuple_info_t target = { CISTPL_LINKTARGET, NULL, NULL };
361     
362     b[0] = CISTPL_LONGLINK_MFC;
363     b[1] = 5*nf + 1;
364     b[2] = nf;
365     b[5*nf+3] = CISTPL_END;
366     b[5*nf+4] = 0;
367     /* Leave space for this tuple and the CISTPL_END tuple */
368     pos = 5*nf+5;
369     for (i = 0; i < nf; i++) {
370         b[3+i*5] = 0;
371         for (j = 0; j < 4; j++)
372             b[4+i*5+j] = ((ofs+pos) >> (8*j)) & 0xff;
373         pos += pack_tuple(&target, b+pos);
374         pos += pack_chain(mfc[i], b+pos);
375     }
376     return ofs+pos;
377 }
378
379 static int pack_cis(tuple_info_t *t, u_char *b)
380 {
381     int n = 0;
382     tuple_info_t device = { CISTPL_DEVICE, NULL, NULL };
383     tuple_info_t nolink = { CISTPL_NO_LINK, NULL, NULL };
384     tuple_info_t end = { CISTPL_END, NULL, NULL };
385     if (t->type != CISTPL_DEVICE)
386         n = pack_tuple(&device, b);
387     while (t) {
388         n += pack_tuple(t, b+n);
389         t = t->next;
390     }
391     if (nf > 0) {
392         n = pack_mfc(n, b+n);
393     } else {
394         n += pack_tuple(&nolink, b+n);
395         n += pack_tuple(&end, b+n);
396     }
397      return n;
398 }
399
400 /*====================================================================*/
401
402 int main(int argc, char *argv[])
403 {
404     int optch, errflg = 0;
405     char *out = NULL;
406     u_char buf[1024];
407     int n;
408     FILE *f;
409
410     while ((optch = getopt(argc, argv, "o:")) != -1) {
411         switch (optch) {
412         case 'o':
413             out = strdup(optarg); break;
414         default:
415             errflg = 1; break;
416         }
417     }
418     if (errflg || (optind < argc-1)) {
419         fprintf(stderr, "usage: %s [-o outfile] [infile]\n",
420                 argv[0]);
421         exit(EXIT_FAILURE);
422     }
423     if (optind < argc) {
424         f = fopen(argv[optind], "r");
425         if (!f) {
426             fprintf(stderr, "could not open '%s': %s\n", argv[optind],
427                     strerror(errno));
428             return -1;
429         }
430     } else
431         f = stdin;
432     parse_cis(f);
433     fclose(f);
434     n = pack_cis(cis_root, buf);
435     if (out) {
436         f = fopen(out, "w");
437         if (!f) {
438             fprintf(stderr, "could not open '%s': %s\n", out,
439                     strerror(errno));
440             return -1;
441         }
442     } else f = stdout;
443     fwrite(buf, n, 1, f);
444     fclose(f);
445     
446     return 0;
447 }