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 };
pack_power(cistpl_power_t * pwr,u_char * b)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
pack_io(cistpl_io_t * p,u_char * b)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
pack_mem(cistpl_mem_t * p,u_char * b)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
pack_irq(cistpl_irq_t * p,u_char * b)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
pack_cftable(cistpl_cftable_entry_t * p,u_char * b)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
pack_speed(u_int speed,u_char * b)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
pack_device(cistpl_device_t * d,u_char * b)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
pack_tuple(tuple_info_t * t,u_char * b)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
pack_chain(tuple_info_t * t,u_char * b)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
pack_mfc(u_int ofs,u_char * b)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
pack_cis(tuple_info_t * t,u_char * b)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
main(int argc,char * argv[])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