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