xref: /haiku/src/bin/pcmcia-cs/pack_cis.c (revision 24159a0c7d6d6dcba9f2a0c1a7c08d2c8167f21b)
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 1.1 (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 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 }
448