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
54tuple_info_t *cis_root = NULL, *mfc[8] = { NULL };
55int nf = 0;
56
57/*======================================================================
58
59    Support routines for packing parts of configuration table entries
60
61======================================================================*/
62
63static u_int mantissa[] = {
64    10, 12, 13, 15, 20, 25, 30, 35,
65    40, 45, 50, 55, 60, 70, 80, 90
66};
67static 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
98static 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
128static 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
156static 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
167static 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
214static 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
234static 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
257static 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
345static 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
357static 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
379static 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
402int 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