1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contains the tuple handlers that are called by the CIS 31 * parser. 32 * 33 * XXX - how about a better explaination?? 34 */ 35 36 #include <sys/types.h> 37 #include <sys/systm.h> 38 #include <sys/user.h> 39 #include <sys/buf.h> 40 #include <sys/file.h> 41 #include <sys/uio.h> 42 #include <sys/conf.h> 43 #include <sys/stat.h> 44 #include <sys/autoconf.h> 45 #include <sys/vtoc.h> 46 #include <sys/dkio.h> 47 #include <sys/ddi.h> 48 #include <sys/sunddi.h> 49 #include <sys/debug.h> 50 #include <sys/ddi_impldefs.h> 51 #include <sys/kstat.h> 52 #include <sys/kmem.h> 53 #include <sys/modctl.h> 54 #include <sys/kobj.h> 55 #include <sys/callb.h> 56 57 #include <sys/pctypes.h> 58 #include <pcmcia/sys/cs_types.h> 59 #include <pcmcia/sys/cis.h> 60 #include <pcmcia/sys/cis_handlers.h> 61 #include <pcmcia/sys/cs.h> 62 #include <pcmcia/sys/cs_priv.h> 63 #include <pcmcia/sys/cis_protos.h> 64 65 /* 66 * Function prototypes 67 */ 68 static void cistpl_pd_parse(cistpl_t *, cistpl_cftable_entry_pwr_t *); 69 static void cis_return_name(cistpl_callout_t *, cistpl_get_tuple_name_t *); 70 71 /* 72 * cis_tuple_handler - call the handler for the tuple described by the 73 * tuple pointer 74 * 75 * cistpl_callout_t *co - pointer to callout structure 76 * array to use to find this tuple 77 * cistpl_t *tp - pointer to a tuple structure 78 * int flags - action for the handler to perform 79 * XXX - we need a description of the flags passed to the tuple handler 80 * void *arg - argument to pass on to tuple handler 81 * 82 * If the tuple is not recognized but is is a vendor-specific tuple, we 83 * set the CISTPLF_VENDOR_SPECIFIC flag in the tuple. 84 * 85 * We return CISTPLF_UNKNOWN if this is an unrecognized tuple as well as 86 * set the CISTPLF_UNKNOWN flag in the tuple list structure. Note 87 * that encountering an unknown tuple is not necessarily an error, 88 * so we don't set the HANDTPL_ERROR flag on the return code. It 89 * is up to the caller to determine what an unrecognized tuple means. 90 * 91 * If this is a recognized tuple, the apropriate tuple handler is called and 92 * the return value from the handler is returned directly to the caller. 93 * 94 * The void *arg is optional, and it's meaning is dependent on the 95 * particular tuple handler called and the flags parameter. 96 * 97 * For the special case of HANDTPL_RETURN_NAME, we don't bother calling the 98 * tuple handler and just return the tuple name to the caller. 99 */ 100 uint32_t 101 cis_tuple_handler(cistpl_callout_t *co, cistpl_t *tp, uint32_t flags, 102 void *arg, cisdata_t subtype) 103 { 104 /* 105 * Check to see if this is a vendor-specific tuple. 106 */ 107 if (CISTPL_IS_VENDOR_SPECIFIC(tp->type)) 108 tp->flags |= CISTPLF_VENDOR_SPECIFIC; 109 110 /* 111 * Scan the callout list until we find the tuple passed to us, or we 112 * encounter a CISTPL_END in the callout list, which signals that 113 * there are no more tuples in the callout list. 114 */ 115 while (co->type != (cisdata_t)CISTPL_END) { 116 if (co->type == tp->type && 117 ((tp->type != CISTPL_FUNCE) || 118 (tp->type == CISTPL_FUNCE && co->subtype == subtype))) { 119 tp->flags &= ~CISTPLF_UNKNOWN; 120 if (flags & HANDTPL_RETURN_NAME) { 121 cis_return_name(co, (cistpl_get_tuple_name_t *)arg); 122 return (CISTPLF_NOERROR); 123 } else { 124 return ((*co->handler) (co, tp, flags, arg)); 125 } /* HANDTPL_RETURN_NAME */ 126 } /* if */ 127 co++; 128 } /* while */ 129 130 /* 131 * If we didn't recognize the tuple and the caller wants the tuple 132 * name back, then return the "unknown tuple" string. At this 133 * point, "co" will be pointing to the last entry in the 134 * callout list. It's not an error to not recognize the tuple 135 * when the operation is HANDTPL_RETURN_NAME. 136 */ 137 if (flags & HANDTPL_RETURN_NAME) { 138 cis_return_name(co, (cistpl_get_tuple_name_t *)arg); 139 return (CISTPLF_NOERROR); 140 } 141 142 tp->flags |= CISTPLF_UNKNOWN; 143 return (CISTPLF_UNKNOWN); 144 } 145 146 /* 147 * cis_no_tuple_handler - this generic tuple handler is used if no special 148 * tuple processing is required for the passed 149 * tuple 150 * 151 * cistpl_callout_t *co - pointer to this tuple's entry in the 152 * tuple callout structure 153 * cistpl_t *tp - pointer to this tuple's entry in the local linked list 154 * int flags - action to perform 155 * 156 * This handler will set the CISTPLF_COPYOK flag if the tuple link is greater 157 * than zero, indicating that it's OK to copy the tuple data body. It 158 * will also set whatever flags are specified in the callout structure. 159 * 160 * We always set the CISTPLF_VALID when we're called with HANDTPL_COPY_DONE. 161 * 162 * We return CISTPLF_UNKNOWN if we're being called to parse the tuple. 163 * 164 * We return CISTPLF_NOERROR in every other case to indicate that this is a 165 * recognized tuple. 166 */ 167 /*ARGSUSED*/ 168 uint32_t 169 cis_no_tuple_handler(cistpl_callout_t *co, cistpl_t *tp, 170 uint32_t flags, void *arg) 171 { 172 if (flags & HANDTPL_SET_FLAGS) { 173 tp->flags |= co->flags; /* XXX - is = the right thing here? */ 174 if (tp->len > 0) 175 tp->flags |= CISTPLF_COPYOK; 176 } 177 178 if (flags & HANDTPL_COPY_DONE) 179 tp->flags |= CISTPLF_VALID; 180 181 if (flags & HANDTPL_PARSE_LTUPLE) 182 return (CISTPLF_UNKNOWN); 183 184 return (CISTPLF_NOERROR); 185 } 186 187 /* 188 * cis_unknown_tuple_handler - this generic tuple handler is used if we don't 189 * understand this tuple 190 * 191 * cistpl_callout_t *co - pointer to this tuple's entry in the 192 * tuple callout structure 193 * cistpl_t *tp - pointer to this tuple's entry in the local linked list 194 * int flags - action to perform 195 * 196 * This handler will not set the CISTPLF_COPYOK flag since we don't know the 197 * contents of a vendor-specific tuple. 198 * 199 * We always set the CISTPLF_VALID when we're called with HANDTPL_COPY_DONE 200 * to specify that we understand this tuple's code, but not it's data 201 * body. 202 * 203 * We return CISTPLF_UNKNOWN if we're being called to parse the tuple or to 204 * perform any other operation. 205 */ 206 /*ARGSUSED*/ 207 uint32_t 208 cis_unknown_tuple_handler(cistpl_callout_t *co, cistpl_t *tp, 209 uint32_t flags, void *arg) 210 { 211 if (flags & HANDTPL_SET_FLAGS) { 212 tp->flags |= co->flags; /* XXX - is = the right thing here? */ 213 return (CISTPLF_NOERROR); 214 } 215 216 if (flags & HANDTPL_COPY_DONE) { 217 tp->flags |= CISTPLF_VALID; 218 return (CISTPLF_NOERROR); 219 } 220 221 return (CISTPLF_UNKNOWN); 222 } 223 224 /* 225 * cistpl_vers_1_handler - handler for the CISTPL_VERS_1 tuple 226 * 227 * void *arg - points to a cistpl_vers_1_t * where the 228 * information is stuffed into 229 */ 230 uint32_t 231 cistpl_vers_1_handler(cistpl_callout_t *co, cistpl_t *tp, 232 uint32_t flags, void *arg) 233 { 234 /* 235 * nothing special about our flags, so just call the 236 * generic handler for this 237 */ 238 if (flags & HANDTPL_SET_FLAGS) 239 return (cis_no_tuple_handler(co, tp, flags, arg)); 240 241 /* 242 * We don't currently validate this tuple. This call will 243 * always set tp->flags |= CISTPLF_VALID. 244 */ 245 if (flags & HANDTPL_COPY_DONE) 246 return (cis_no_tuple_handler(co, tp, flags, arg)); 247 248 if (flags & HANDTPL_PARSE_LTUPLE) { 249 cistpl_vers_1_t *cs = (cistpl_vers_1_t *)arg; 250 251 252 RESET_TP(tp); 253 254 cs->major = GET_BYTE(tp); 255 cs->minor = GET_BYTE(tp); 256 for (cs->ns = 0; GET_LEN(tp) > 0 && 257 /* CSTYLED */ 258 cs->ns < CISTPL_VERS_1_MAX_PROD_STRINGS; ) { 259 (void) strcpy(cs->pi[cs->ns++], cis_getstr(tp)); 260 } /* for */ 261 } /* HANDTPL_PARSE_LTUPLE */ 262 263 return (CISTPLF_NOERROR); 264 } 265 266 /* 267 * cistpl_config_handler - handler for the CISTPL_CONFIG tuple 268 * 269 * void *arg - points to a XXX where the information is stuffed into 270 * 271 * For the first ten config registers we set the present flags in the 272 * cistpl_config_t if the register exists. The flags that we use 273 * for this are the same as the flags reguired for the Card Services 274 * RequestConfiguration function and they can be used by clients 275 * directly without requiring any remapping of values. 276 * 277 * XXX we don't handle TPCC_SBTPL subtuples yet 278 */ 279 280 uint32_t config_regs_present_map[] = { 281 CONFIG_OPTION_REG_PRESENT, /* COR present */ 282 CONFIG_STATUS_REG_PRESENT, /* STAT reg present */ 283 CONFIG_PINREPL_REG_PRESENT, /* PRR present */ 284 CONFIG_COPY_REG_PRESENT, /* COPY reg present */ 285 CONFIG_EXSTAT_REG_PRESENT, /* EXSTAT reg present */ 286 CONFIG_IOBASE0_REG_PRESENT, /* IOBASE0 reg present */ 287 CONFIG_IOBASE1_REG_PRESENT, /* IOBASE1 reg present */ 288 CONFIG_IOBASE2_REG_PRESENT, /* IOBASE2 reg present */ 289 CONFIG_IOBASE3_REG_PRESENT, /* IOBASE3 reg present */ 290 CONFIG_IOLIMIT_REG_PRESENT, /* IOLIMIT reg present */ 291 }; 292 293 uint32_t 294 cistpl_config_handler(cistpl_callout_t *co, cistpl_t *tp, 295 uint32_t flags, void *arg) 296 { 297 cisdata_t tpcc_sz; 298 int i, n, nrb, na, hr = 0; 299 300 /* 301 * nothing special about our flags, so just call the 302 * generic handler for this 303 */ 304 if (flags & HANDTPL_SET_FLAGS) 305 return (cis_no_tuple_handler(co, tp, flags, arg)); 306 307 /* 308 * We don't currently validate this tuple. This call will 309 * always set tp->flags |= CISTPLF_VALID. 310 */ 311 if (flags & HANDTPL_COPY_DONE) 312 return (cis_no_tuple_handler(co, tp, flags, arg)); 313 314 if (flags & HANDTPL_PARSE_LTUPLE) { 315 cistpl_config_t *cr = (cistpl_config_t *)arg; 316 int crn = 0; 317 318 RESET_TP(tp); 319 320 tpcc_sz = GET_BYTE(tp); /* config regs size fields */ 321 cr->last = GET_BYTE(tp); /* last config index */ 322 323 na = (tpcc_sz&3)+1; /* config regs address bytes */ 324 nrb = ((tpcc_sz>>2)&0x0f)+1; /* number of bytes in config */ 325 /* regs presence mask */ 326 327 /* 328 * Construct the base offset address for the config registers. 329 * We jump through these hoops because the base address 330 * can be between one and four bytes in length. 331 */ 332 cr->base = 0; 333 n = na; 334 while (n--) 335 cr->base |= ((GET_BYTE(tp) & 0x0ff) << 336 (8 * (na - (n+1)))); 337 338 /* 339 * Go through the config register presense mask bit by bit and 340 * figure out which config registers are present and which 341 * aren't. 342 * For the first ten config registers, set the appropriate 343 * bits in the cr->present member so that the caller 344 * doesn't have to do this. 345 */ 346 cr->nr = 0; 347 cr->present = 0; 348 n = nrb; 349 while (n--) { 350 for (i = 0; i < 8; i++, crn++) { 351 if (LOOK_BYTE(tp) & (1<<i)) { 352 if (crn < (sizeof (config_regs_present_map)/ 353 sizeof (uint32_t))) 354 cr->present |= 355 config_regs_present_map[crn]; 356 cr->nr++; 357 cr->hr = hr; 358 cr->regs[hr] = MAKE_CONFIG_REG_ADDR( 359 cr->base, hr); 360 } /* LOOK_BYTE */ 361 hr++; 362 } /* for */ 363 (void) GET_BYTE(tp); 364 } /* while */ 365 } 366 367 return (CISTPLF_NOERROR); 368 } 369 370 /* 371 * cistpl_device_handler - handler for the CISTPL_DEVICE, CISTPL_DEVICE_A, 372 * CISTPL_DEVICE_OC and CISTPL_DEVICE_OA tuples 373 * 374 * void *arg - points to a cistpl_device_t * where the 375 * information is stuffed into 376 * 377 * XXX - we only handle CISTPL_DEVICE_MAX_DEVICES device descriptions 378 * described in the tuple 379 */ 380 uint32_t 381 cistpl_device_handler(cistpl_callout_t *co, cistpl_t *tp, 382 uint32_t flags, void *arg) 383 { 384 cisdata_t dev_id; 385 386 /* 387 * nothing special about our flags, so just call the 388 * generic handler for this 389 */ 390 if (flags & HANDTPL_SET_FLAGS) 391 return (cis_no_tuple_handler(co, tp, flags, arg)); 392 393 /* 394 * We don't currently validate this tuple. This call will 395 * always set tp->flags |= CISTPLF_VALID. 396 */ 397 if (flags & HANDTPL_COPY_DONE) 398 return (cis_no_tuple_handler(co, tp, flags, arg)); 399 400 if (flags & HANDTPL_PARSE_LTUPLE) { 401 convert_speed_t convert_speed; 402 cistpl_device_t *dt = (cistpl_device_t *)arg; 403 cistpl_device_node_t *cdn; 404 405 /* 406 * XXX - fix this to look for more than one device definition 407 * XXX - fix this to handle the OC fields for 408 * CISTPL_DEVICE_OC and CISTPL_DEVICE_OA 409 */ 410 dt->num_devices = 1; 411 cdn = &dt->devnode[0]; 412 413 cdn->flags = 0; 414 415 RESET_TP(tp); 416 417 dev_id = GET_BYTE(tp); 418 419 /* 420 * Get the device speed code. If it's 7, then there is an 421 * extended speed code table in use, so parse that. 422 * If it's anything else, get the speed information 423 * directly from the device speed code. 424 */ 425 if ((dev_id & 7) == 7) { 426 cdn->nS_speed = cistpl_devspeed(tp, 0, CISTPL_DEVSPEED_EXT); 427 } else { 428 cdn->nS_speed = cistpl_devspeed(NULL, dev_id, 429 CISTPL_DEVSPEED_TABLE); 430 } 431 432 /* 433 * Convert the speed in nS to a device speed code. 434 * XXX - should check return code from cis_convert_devspeed() 435 */ 436 convert_speed.Attributes = CONVERT_NS_TO_DEVSPEED; 437 convert_speed.nS = cdn->nS_speed; 438 (void) cis_convert_devspeed(&convert_speed); 439 cdn->speed = convert_speed.devspeed; 440 441 if (dev_id & 8) 442 cdn->flags |= CISTPL_DEVICE_WPS; 443 444 /* 445 * Set the device type. Note that we take the raw value 446 * from the tuple and pass it back to the caller. 447 * If the device type codes in the standard change, 448 * we will have to change our flags as well. 449 */ 450 cdn->type = (dev_id>>4) & 0x0f; 451 452 /* 453 * XXX - what about the device_size byte? Is the spec wrong? 454 */ 455 cdn->size = GET_BYTE(tp); 456 /* check for end of list */ 457 if (cdn->size != 0x0ff) { 458 convert_size_t convert_size; 459 460 convert_size.devsize = cdn->size; 461 convert_size.Attributes = CONVERT_DEVSIZE_TO_BYTES; 462 (void) cis_convert_devsize(&convert_size); 463 cdn->size_in_bytes = convert_size.bytes; 464 } 465 } 466 467 return (CISTPLF_NOERROR); 468 } 469 470 /* 471 * cistpl_cftable_handler - handler for the CISTPL_CFTABLE_ENTRY tuple 472 * 473 * void *arg - points to a XXX where the information is stuffed into 474 * 475 * Return: CISTPLF_NOERROR - if no error parsing tuple 476 * HANDTPL_ERROR - if error parsing tuple 477 */ 478 extern uint32_t cistpl_cftable_io_size_table[]; 479 extern uint32_t cistpl_cftable_shift_table[]; 480 481 uint32_t 482 cistpl_cftable_handler(cistpl_callout_t *co, cistpl_t *tp, 483 uint32_t flags, void *arg) 484 { 485 cisdata_t tpce_indx, tpce_fs, tpce_td, sf, tpce_io, nr; 486 cisdata_t ior_desc, tpce_ir, tpce_msd; 487 int i, j; 488 489 /* 490 * nothing special about our flags, so just call the 491 * generic handler for this 492 */ 493 if (flags & HANDTPL_SET_FLAGS) 494 return (cis_no_tuple_handler(co, tp, flags, arg)); 495 496 /* 497 * We don't currently validate this tuple. This call will 498 * always set tp->flags |= CISTPLF_VALID. 499 */ 500 if (flags & HANDTPL_COPY_DONE) 501 return (cis_no_tuple_handler(co, tp, flags, arg)); 502 503 if (flags & HANDTPL_PARSE_LTUPLE) { 504 cistpl_cftable_entry_t *ce = (cistpl_cftable_entry_t *)arg; 505 506 RESET_TP(tp); 507 508 /* 509 * Check to see if we have an interface description byte. If 510 * we do, grab it and give it directly to the caller, and 511 * set a flag so the caller knows that it's there. 512 * We also setup the appropriate values in the ce->pin member 513 * so that clients can feed this value directly to the 514 * Card Services RequestConfiguration call. 515 */ 516 if ((tpce_indx = GET_BYTE(tp)) & CISTPL_CFTABLE_TPCE_IFM) { 517 ce->ifc = GET_BYTE(tp); 518 519 ce->pin = 0; 520 521 if (ce->ifc & CISTPL_CFTABLE_TPCE_IF_BVD) 522 ce->pin |= (PRR_BVD1_STATUS | PRR_BVD2_STATUS | 523 PRR_BVD1_EVENT | PRR_BVD2_EVENT); 524 if (ce->ifc & CISTPL_CFTABLE_TPCE_IF_WP) 525 ce->pin |= (PRR_WP_STATUS | PRR_WP_EVENT); 526 if (ce->ifc & CISTPL_CFTABLE_TPCE_IF_RDY) 527 ce->pin |= (PRR_READY_STATUS | PRR_READY_EVENT); 528 529 ce->flags |= CISTPL_CFTABLE_TPCE_IF; 530 } 531 532 /* 533 * Return the configuration index to the caller, and set the 534 * default configuration flag if this is a default 535 * configuration. 536 */ 537 ce->index = tpce_indx & CISTPL_CFTABLE_TPCE_CFGENTRYM; 538 if (tpce_indx & CISTPL_CFTABLE_TPCE_DEFAULTM) 539 ce->flags |= CISTPL_CFTABLE_TPCE_DEFAULT; 540 541 /* 542 * Feature selection flags. 543 */ 544 tpce_fs = GET_BYTE(tp); 545 546 /* 547 * See what types of power information are available, 548 * and if there is any, set the global power 549 * information flag as well as a flag for each 550 * power description available. 551 */ 552 if (tpce_fs & CISTPL_CFTABLE_TPCE_FS_PWRM) { 553 cistpl_cftable_entry_pd_t *pd = &ce->pd; 554 555 ce->flags |= CISTPL_CFTABLE_TPCE_FS_PWR; 556 557 switch (tpce_fs & CISTPL_CFTABLE_TPCE_FS_PWRM) { 558 case CISTPL_CFTABLE_TPCE_FS_PWR_VPP2M: 559 pd->flags |= CISTPL_CFTABLE_TPCE_FS_PWR_VPP2; 560 /* FALLTHROUGH */ 561 case CISTPL_CFTABLE_TPCE_FS_PWR_VPP1M: 562 pd->flags |= CISTPL_CFTABLE_TPCE_FS_PWR_VPP1; 563 /* FALLTHROUGH */ 564 case CISTPL_CFTABLE_TPCE_FS_PWR_VCCM: 565 pd->flags |= CISTPL_CFTABLE_TPCE_FS_PWR_VCC; 566 } /* switch */ 567 } /* if (CISTPL_CFTABLE_TPCE_FS_PWRM) */ 568 569 /* 570 * Set up the global memory information flag. 571 */ 572 if (tpce_fs & CISTPL_CFTABLE_TPCE_FS_MEMM) 573 ce->flags |= CISTPL_CFTABLE_TPCE_FS_MEM; 574 575 /* 576 * Parse the various power description structures. 577 */ 578 if (ce->flags & CISTPL_CFTABLE_TPCE_FS_PWR) { 579 cistpl_cftable_entry_pd_t *pd = &ce->pd; 580 cistpl_cftable_entry_pwr_t *pwr; 581 /* 582 * Collect any Vcc information. 583 */ 584 if (pd->flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) { 585 pwr = &pd->pd_vcc; 586 cistpl_pd_parse(tp, pwr); 587 } 588 /* 589 * Collect any Vpp1 information. 590 */ 591 if (pd->flags & CISTPL_CFTABLE_TPCE_FS_PWR_VPP1) { 592 pwr = &pd->pd_vpp1; 593 cistpl_pd_parse(tp, pwr); 594 } 595 /* 596 * Collect any Vpp2 information. 597 */ 598 if (pd->flags & CISTPL_CFTABLE_TPCE_FS_PWR_VPP2) { 599 pwr = &pd->pd_vpp2; 600 cistpl_pd_parse(tp, pwr); 601 } 602 } /* if (CISTPL_CFTABLE_TPCE_FS_PWR) */ 603 604 /* 605 * Check to see if there's any timing information, and if 606 * so, parse the tuple data and store it in the 607 * caller's structure. Set a flag in the global 608 * flag field indicating that there is timing information. 609 */ 610 if (tpce_fs & CISTPL_CFTABLE_TPCE_FS_TDM) { 611 convert_speed_t convert_speed; 612 cistpl_cftable_entry_speed_t *sp = &ce->speed; 613 ce->flags |= CISTPL_CFTABLE_TPCE_FS_TD; 614 tpce_td = GET_BYTE(tp); 615 /* 616 * Parse TPCE_TD to get the various timing 617 * scale factors. Each scale factor has 618 * a value that indicates that the particular 619 * timing parameter doesn't exist. 620 */ 621 if ((sf = (tpce_td & 622 CISTPL_CFTABLE_TPCE_FS_TD_WAITM)) != 623 CISTPL_CFTABLE_TPCE_FS_TD_WAITM) { 624 sp->nS_wait = cistpl_devspeed(tp, 625 GET_TPCE_FS_TD_WAITS(sf), 626 CISTPL_DEVSPEED_EXT); 627 convert_speed.Attributes = 628 CONVERT_NS_TO_DEVSPEED; 629 convert_speed.nS = sp->nS_wait; 630 (void) cis_convert_devspeed(&convert_speed); 631 sp->wait = convert_speed.devspeed; 632 sp->flags |= CISTPL_CFTABLE_TPCE_FS_TD_WAIT; 633 } 634 635 if ((sf = (tpce_td & CISTPL_CFTABLE_TPCE_FS_TD_RDYM)) != 636 CISTPL_CFTABLE_TPCE_FS_TD_RDYM) { 637 sp->nS_rdybsy = cistpl_devspeed(tp, 638 GET_TPCE_FS_TD_RDYS(sf), 639 CISTPL_DEVSPEED_EXT); 640 convert_speed.Attributes = 641 CONVERT_NS_TO_DEVSPEED; 642 convert_speed.nS = sp->nS_rdybsy; 643 (void) cis_convert_devspeed(&convert_speed); 644 sp->rdybsy = convert_speed.devspeed; 645 sp->flags |= CISTPL_CFTABLE_TPCE_FS_TD_RDY; 646 } 647 648 if ((sf = (tpce_td & 649 CISTPL_CFTABLE_TPCE_FS_TD_RSVDM)) != 650 CISTPL_CFTABLE_TPCE_FS_TD_RSVDM) { 651 sp->nS_rsvd = cistpl_devspeed(tp, 652 GET_TPCE_FS_TD_RSVDS(sf), 653 CISTPL_DEVSPEED_EXT); 654 convert_speed.Attributes = 655 CONVERT_NS_TO_DEVSPEED; 656 convert_speed.nS = sp->nS_rsvd; 657 (void) cis_convert_devspeed(&convert_speed); 658 sp->rsvd = convert_speed.devspeed; 659 sp->flags |= CISTPL_CFTABLE_TPCE_FS_TD_RSVD; 660 } 661 } /* if (CISTPL_CFTABLE_TPCE_FS_TDM) */ 662 663 664 /* 665 * Parse any I/O address information. If there is I/O 666 * inforamtion, set a flag in the global flag field 667 * to let the caller know. 668 */ 669 if (tpce_fs & CISTPL_CFTABLE_TPCE_FS_IOM) { 670 cistpl_cftable_entry_io_t *io = &ce->io; 671 672 ce->flags |= CISTPL_CFTABLE_TPCE_FS_IO; 673 tpce_io = GET_BYTE(tp); 674 /* 675 * Pass any I/O flags that are in the tuple directly 676 * to the caller. 677 */ 678 io->flags = tpce_io; 679 io->addr_lines = tpce_io & 680 CISTPL_CFTABLE_TPCE_FS_IO_ALM; 681 /* 682 * If there are any ranges, extract the number of 683 * ranges and the range descriptions. 684 */ 685 if (tpce_io & CISTPL_CFTABLE_TPCE_FS_IO_RANGEM) { 686 cistpl_cftable_entry_io_range_t *ior; 687 ior_desc = GET_BYTE(tp); 688 /* 689 * Number of I/O ranges is the value specified 690 * in the tuple plus one, so there's 691 * always at least one I/O range if the 692 * CISTPL_CFTABLE_TPCE_FS_IO_RANGEM bit 693 * in the I/O flags register is set. 694 */ 695 nr = (ior_desc & 0x0f) + 1; 696 io->ranges = nr; 697 /* 698 * Cycle through each I/O range. 699 */ 700 for (i = 0; i < (int)nr; i++) { 701 ior = &io->range[i]; 702 ior->addr = 0; 703 ior->length = 0; 704 /* 705 * Gather the address information. 706 * It's OK if there's no address 707 * information in which case this 708 * loop will never execute. 709 */ 710 for (j = 0; j < 711 cistpl_cftable_io_size_table[ 712 (ior_desc>>4)&3]; 713 j++) 714 ior->addr |= (GET_BYTE(tp) << 715 cistpl_cftable_shift_table[j]); 716 /* 717 * Gather the length information. 718 * It's OK if there's no length 719 * information in which case this 720 * loop will never execute. 721 */ 722 for (j = 0; j < 723 cistpl_cftable_io_size_table[ 724 (ior_desc>>6)&3]; 725 j++) 726 ior->length |= (GET_BYTE(tp) << 727 cistpl_cftable_shift_table[j]); 728 } /* for (nr) */ 729 } /* if (CISTPL_CFTABLE_TPCE_FS_IO_RANGEM) */ 730 } /* if (CISTPL_CFTABLE_TPCE_FS_IOM) */ 731 732 /* 733 * Parse any IRQ information. If there is IRQ inforamtion, 734 * set a flag in the global flag field to let the 735 * caller know. 736 */ 737 if (tpce_fs & CISTPL_CFTABLE_TPCE_FS_IRQM) { 738 cistpl_cftable_entry_irq_t *irq = &ce->irq; 739 740 ce->flags |= CISTPL_CFTABLE_TPCE_FS_IRQ; 741 tpce_ir = GET_BYTE(tp); 742 /* 743 * Pass any IRQ flags that are in the tuple directly 744 * to the caller. 745 */ 746 irq->flags = tpce_ir; 747 /* 748 * Check for and parse the extended IRQ bitmask 749 * if it exists. 750 */ 751 if (tpce_ir & CISTPL_CFTABLE_TPCE_FS_IRQ_MASKM) { 752 irq->irqs = GET_BYTE(tp) & 0x0ff; 753 irq->irqs |= (GET_BYTE(tp) << 8)&0x0ff00; 754 } else { 755 irq->irqs = (1<< (tpce_ir&0x0f)); 756 } 757 } /* if (CISTPL_CFTABLE_TPCE_FS_IRQM) */ 758 759 /* 760 * Parse any memory information. 761 * 762 * XXX - should be a cleaner way to parse this information. 763 */ 764 if (ce->flags & CISTPL_CFTABLE_TPCE_FS_MEM) { 765 cistpl_cftable_entry_mem_t *mem = &ce->mem; 766 cistpl_cftable_entry_mem_window_t *win; 767 /* 768 * Switch on the type of memory description 769 * information that is available. 770 */ 771 switch (tpce_fs & CISTPL_CFTABLE_TPCE_FS_MEMM) { 772 /* 773 * variable length memory space description 774 */ 775 case CISTPL_CFTABLE_TPCE_FS_MEM3M: 776 mem->flags |= CISTPL_CFTABLE_TPCE_FS_MEM3; 777 /* memory space descriptor */ 778 tpce_msd = GET_BYTE(tp); 779 mem->windows = ((tpce_msd & 780 (CISTPL_CFTABLE_ENTRY_MAX_MEM_WINDOWS - 781 1)) + 1); 782 /* 783 * If there's host address information, let 784 * the caller know. 785 */ 786 if (tpce_msd & CISTPL_CFTABLE_TPCE_FS_MEM_HOSTM) 787 mem->flags |= 788 CISTPL_CFTABLE_TPCE_FS_MEM_HOST; 789 /* 790 * Cycle through each window space description 791 * and collect all the interesting bits. 792 */ 793 for (i = 0; i < mem->windows; i++) { 794 win = &mem->window[i]; 795 win->length = 0; 796 win->card_addr = 0; 797 win->host_addr = 0; 798 /* 799 * Gather the length information. 800 * It's OK if there's no length 801 * information in which case this 802 * loop will never execute. 803 */ 804 for (j = 0; j < 805 (int)((tpce_msd>>3)&3); j++) 806 win->length |= (GET_BYTE(tp) << 807 cistpl_cftable_shift_table[j]); 808 /* 809 * Gather the card address information. 810 * It's OK if there's no card 811 * address information in which 812 * case this loop will never 813 * execute. 814 */ 815 for (j = 0; j < 816 (int)((tpce_msd>>5)&3); j++) 817 win->card_addr |= 818 (GET_BYTE(tp) << 819 cistpl_cftable_shift_table[j]); 820 /* 821 * If there's a host address 822 * description, grab that 823 * as well. 824 */ 825 if (mem->flags & 826 CISTPL_CFTABLE_TPCE_FS_MEM_HOST) { 827 /* 828 * Gather the host address 829 * information. It's OK 830 * if there's no host 831 * address information in 832 * which case this loop 833 * will never execute. 834 * Note that we use the card 835 * address size to 836 * determine how many 837 * bytes of host address 838 * are present. 839 */ 840 for (j = 0; j < 841 (int)((tpce_msd>>5)&3); 842 j++) 843 win->host_addr |= 844 (GET_BYTE(tp) << 845 cistpl_cftable_shift_table[j]); 846 } else { 847 /* 848 * No host address information, 849 * so the host address is 850 * equal to the card 851 * address. 852 */ 853 win->host_addr = win->card_addr; 854 } 855 } /* for (i<mem->windows) */ 856 break; 857 /* 858 * single length and card base address specified 859 */ 860 case CISTPL_CFTABLE_TPCE_FS_MEM2M: 861 mem->flags |= CISTPL_CFTABLE_TPCE_FS_MEM2; 862 win = &mem->window[0]; 863 mem->windows = 1; 864 /* 865 * Construct the size of the window. 866 */ 867 win->length = GET_BYTE(tp); 868 win->length |= (GET_BYTE(tp)<<8); 869 win->length *= 870 CISTPL_CFTABLE_TPCE_FS_MEM_PGSIZE; 871 872 /* 873 * Construct the card base address. 874 */ 875 win->card_addr = GET_BYTE(tp); 876 win->card_addr |= (GET_BYTE(tp)<<8); 877 win->card_addr *= 878 CISTPL_CFTABLE_TPCE_FS_MEM_PGSIZE; 879 880 /* 881 * In this mode, both the host base address 882 * and the card base address are equal. 883 */ 884 win->host_addr = win->card_addr; 885 break; 886 /* 887 * single length specified 888 */ 889 case CISTPL_CFTABLE_TPCE_FS_MEM1M: 890 mem->flags |= CISTPL_CFTABLE_TPCE_FS_MEM1; 891 win = &mem->window[0]; 892 mem->windows = 1; 893 win->card_addr = 0; 894 win->host_addr = 0; 895 /* 896 * Construct the size of the window. 897 */ 898 win->length = GET_BYTE(tp); 899 win->length |= (GET_BYTE(tp)<<8); 900 win->length *= 901 CISTPL_CFTABLE_TPCE_FS_MEM_PGSIZE; 902 break; 903 } /* switch (CISTPL_CFTABLE_TPCE_FS_MEMM) */ 904 } /* if (CISTPL_CFTABLE_TPCE_FS_MEM) */ 905 906 /* 907 * Check for and parse any miscellaneous information. 908 * 909 * We only understand how to parse the first 910 * CISTPL_CFTABLE_TPCE_FS_MISC_MAX extension 911 * bytes specified in the PC Card 95 standard; 912 * we throw away any other extension bytes that 913 * are past these bytes. 914 * XXX Note that the assumption here is that the 915 * size of cistpl_cftable_entry_misc_t->flags 916 * is at least CISTPL_CFTABLE_TPCE_FS_MISC_MAX 917 * bytes in length. 918 */ 919 if (tpce_fs & CISTPL_CFTABLE_TPCE_FS_MISCM) { 920 cistpl_cftable_entry_misc_t *misc = &ce->misc; 921 int mb = CISTPL_CFTABLE_TPCE_FS_MISC_MAX; 922 923 ce->flags |= CISTPL_CFTABLE_TPCE_FS_MISC; 924 misc->flags = 0; 925 926 do { 927 if (mb) { 928 misc->flags = (misc->flags << 8) | LOOK_BYTE(tp); 929 mb--; 930 } 931 } while ((GET_BYTE(tp) & CISTPL_EXT_BIT) && 932 (!(tp->flags & CISTPLF_MEM_ERR))); 933 934 /* 935 * Check to see if we tried to read past the 936 * end of the tuple data; if we have, 937 * there's no point in trying to parse 938 * any more of the tuple. 939 */ 940 if (tp->flags & CISTPLF_MEM_ERR) 941 return (HANDTPL_ERROR); 942 } /* if (CISTPL_CFTABLE_TPCE_FS_MISCM) */ 943 944 /* 945 * Check for and parse any additional subtuple 946 * information. We know that there is 947 * additional information if we haven't 948 * reached the end of the tuple data area 949 * and if the additional information is 950 * in standard tuple format. 951 * If we don't recognize the additional info, 952 * then just silently ignore it, don't 953 * flag it as an error. 954 */ 955 #ifdef PARSE_STCE_TUPLES 956 if (GET_LEN(tp) > 0) { 957 958 ce->flags |= CISTPL_CFTABLE_TPCE_FS_STCE_EV 959 ce->flags |= CISTPL_CFTABLE_TPCE_FS_STCE_PD 960 #endif 961 962 } /* if (HANDTPL_PARSE_LTUPLE) */ 963 964 return (CISTPLF_NOERROR); 965 } 966 967 /* 968 * cistpl_pd_parse - read and parse a power description structure 969 * 970 * cisdata_t **ddp - pointer to pointer tuple data area 971 * cistpl_cftable_entry_pwr_t *pd - pointer to local power description 972 * structure 973 */ 974 static void 975 cistpl_pd_parse(cistpl_t *tp, cistpl_cftable_entry_pwr_t *pd) 976 { 977 cisdata_t pdesc; 978 979 pdesc = GET_BYTE(tp); /* power description selector */ 980 981 /* nominal supply voltage */ 982 if (pdesc & CISTPL_CFTABLE_PD_NOMV) { 983 pd->nomV = cistpl_expd_parse(tp, &pd->nomV_flags) / 100; 984 pd->nomV_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS); 985 } 986 987 /* minimum supply voltage */ 988 if (pdesc & CISTPL_CFTABLE_PD_MINV) { 989 pd->minV = cistpl_expd_parse(tp, &pd->minV_flags) / 100; 990 pd->minV_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS); 991 } 992 993 /* maximum supply voltage */ 994 if (pdesc & CISTPL_CFTABLE_PD_MAXV) { 995 pd->maxV = cistpl_expd_parse(tp, &pd->maxV_flags) / 100; 996 pd->maxV_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS); 997 } 998 999 /* continuous supply current */ 1000 if (pdesc & CISTPL_CFTABLE_PD_STATICI) { 1001 pd->staticI_flags |= CISTPL_CFTABLE_PD_MUL10; 1002 pd->staticI = cistpl_expd_parse(tp, &pd->staticI_flags); 1003 pd->staticI_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS); 1004 } 1005 1006 /* maximum current required averaged over 1 second */ 1007 if (pdesc & CISTPL_CFTABLE_PD_AVGI) { 1008 pd->avgI_flags |= CISTPL_CFTABLE_PD_MUL10; 1009 pd->avgI = cistpl_expd_parse(tp, &pd->avgI_flags); 1010 pd->avgI_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS); 1011 } 1012 1013 /* maximum current required averaged over 10mS */ 1014 if (pdesc & CISTPL_CFTABLE_PD_PEAKI) { 1015 pd->peakI_flags |= CISTPL_CFTABLE_PD_MUL10; 1016 pd->peakI = cistpl_expd_parse(tp, &pd->peakI_flags); 1017 pd->peakI_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS); 1018 } 1019 1020 /* power down supply curent required */ 1021 if (pdesc & CISTPL_CFTABLE_PD_PDOWNI) { 1022 pd->pdownI_flags |= CISTPL_CFTABLE_PD_MUL10; 1023 pd->pdownI = cistpl_expd_parse(tp, &pd->pdownI_flags); 1024 pd->pdownI_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS); 1025 } 1026 } 1027 1028 /* 1029 * cistpl_expd_parse - read and parse an extended power description structure 1030 * 1031 * cistpl_t *tp - pointer to pointer tuple data area 1032 * int *flags - flags that get for this parameter: 1033 * CISTPL_CFTABLE_PD_NC_SLEEP - no connection on 1034 * sleep/power down 1035 * CISTPL_CFTABLE_PD_ZERO - zero value required 1036 * CISTPL_CFTABLE_PD_NC - no connection ever 1037 * 1038 * The power consumption is returned in the following units: 1039 * 1040 * voltage - milliVOLTS 1041 * current - microAMPS 1042 */ 1043 extern cistpl_pd_struct_t cistpl_pd_struct; 1044 1045 uint32_t 1046 cistpl_expd_parse(cistpl_t *tp, uint32_t *flags) 1047 { 1048 cisdata_t pdesc; 1049 uint32_t exponent, mantisa, val, digits = 0; 1050 1051 /* 1052 * Get the power description parameter byte and break it up 1053 * into mantissa and exponent. 1054 */ 1055 pdesc = GET_BYTE(tp); 1056 exponent = pdesc&7; 1057 mantisa = (pdesc>>3)&0x0f; 1058 1059 if (pdesc & CISTPL_EXT_BIT) { 1060 do { 1061 if (LOOK_BYTE(tp) <= 0x63) 1062 digits = LOOK_BYTE(tp); 1063 if (LOOK_BYTE(tp) == CISTPL_CFTABLE_PD_NC_SLEEPM) 1064 *flags |= CISTPL_CFTABLE_PD_NC_SLEEP; 1065 if (LOOK_BYTE(tp) == CISTPL_CFTABLE_PD_ZEROM) 1066 *flags |= CISTPL_CFTABLE_PD_ZERO; 1067 if (LOOK_BYTE(tp) == CISTPL_CFTABLE_PD_NCM) 1068 *flags |= CISTPL_CFTABLE_PD_NC; 1069 } while (GET_BYTE(tp) & CISTPL_EXT_BIT); 1070 } 1071 1072 val = CISTPL_PD_MAN(mantisa) * CISTPL_PD_EXP(exponent); 1073 1074 /* 1075 * If we have to multiply the power value by ten, then just 1076 * don't bother dividing. 1077 */ 1078 if (! (*flags & CISTPL_CFTABLE_PD_MUL10)) 1079 val = val/10; /* do this since our mantissa table is X 10 */ 1080 1081 /* 1082 * If we need to add some digits to the right of the decimal, do 1083 * that here. 1084 */ 1085 if (exponent) 1086 val = val + (digits * CISTPL_PD_EXP(exponent-1)); 1087 1088 val /= 1000; 1089 1090 return (val); 1091 } 1092 1093 /* 1094 * cistpl_devspeed - returns device speed in nS 1095 * 1096 * cistpl_t *tp - tuple pointer. 1097 * cisdata_t spindex - device speed table index 1098 * int flags - operation flags 1099 * CISTPL_DEVSPEED_TABLE: 1100 * Use the spindex argument as an index into a simple 1101 * device speed table. ref: PCMCIA Release 2.01 1102 * Card Metaformat pg. 5-14 table 5-12. 1103 * When this flag is set, the spindex argument is ignored. 1104 * CISTPL_DEVSPEED_EXT: 1105 * Use the tp argument to access the 1106 * tuple data area containing an extended speed 1107 * code table. ref: PCMCIA Release 2.01 Card 1108 * Metaformat pg. 5-15 table 5-13. 1109 * The tp->read argument must point to the first byte of 1110 * an extended speed code table. 1111 * When this flag is set, the spindex argument is 1112 * used as a power-of-10 scale factor. We only allow 1113 * a maximum scale factor of 10^16. 1114 * 1115 * The device speed is returned in nS for all combinations of flags and 1116 * speed table entries. 1117 * 1118 * Note if you pass the CISTPL_DEVSPEED_TABLE with a spindex index that 1119 * refers to an extended speed table, you will get back an undefined 1120 * speed value. 1121 */ 1122 extern cistpl_devspeed_struct_t cistpl_devspeed_struct; 1123 1124 uint32_t 1125 cistpl_devspeed(cistpl_t *tp, cisdata_t spindex, uint32_t flags) 1126 { 1127 int scale = 1, first; 1128 cisdata_t exspeed; 1129 int exponent, mantisa; 1130 uint32_t speed; 1131 1132 switch (flags) { 1133 case CISTPL_DEVSPEED_TABLE: 1134 speed = CISTPL_DEVSPEED_TBL(spindex); 1135 break; 1136 case CISTPL_DEVSPEED_EXT: 1137 do { 1138 exspeed = GET_BYTE(tp); 1139 first = 1; 1140 if (first) { 1141 /* 1142 * XXX - ugh! we don't understand additional 1143 * exspeed bytes 1144 */ 1145 first = 0; 1146 exponent = (exspeed & 0x07); 1147 mantisa = (exspeed >> 3) & 0x0f; 1148 spindex &= 0x0f; /* only allow 10^16 */ 1149 while (spindex--) 1150 scale *= 10; 1151 } /* if (first) */ 1152 } while (exspeed & CISTPL_EXT_BIT); 1153 speed = scale * CISTPL_DEVSPEED_MAN(mantisa) * 1154 CISTPL_DEVSPEED_EXP(exponent); 1155 speed = speed/10; /* XXX - mantissa table is all X 10 */ 1156 break; 1157 default: 1158 break; 1159 } 1160 1161 return (speed); 1162 } 1163 1164 /* 1165 * cistpl_vers_2_handler - handler for the CISTPL_VERS_2 tuple 1166 * 1167 * void *arg - points to a XXX where the information is stuffed into 1168 */ 1169 uint32_t 1170 cistpl_vers_2_handler(cistpl_callout_t *co, cistpl_t *tp, 1171 uint32_t flags, void *arg) 1172 { 1173 /* 1174 * nothing special about our flags, so just call the 1175 * generic handler for this 1176 */ 1177 if (flags & HANDTPL_SET_FLAGS) 1178 return (cis_no_tuple_handler(co, tp, flags, arg)); 1179 1180 /* 1181 * We don't currently validate this tuple. This call will 1182 * always set tp->flags |= CISTPLF_VALID. 1183 */ 1184 if (flags & HANDTPL_COPY_DONE) 1185 return (cis_no_tuple_handler(co, tp, flags, arg)); 1186 1187 if (flags & HANDTPL_PARSE_LTUPLE) { 1188 cistpl_vers_2_t *cs = (cistpl_vers_2_t *)arg; 1189 1190 RESET_TP(tp); 1191 1192 cs->vers = GET_BYTE(tp); 1193 cs->comply = GET_BYTE(tp); 1194 cs->dindex = GET_SHORT(tp); 1195 1196 cs->reserved = GET_SHORT(tp); 1197 1198 cs->vspec8 = GET_BYTE(tp); 1199 cs->vspec9 = GET_BYTE(tp); 1200 cs->nhdr = GET_BYTE(tp); 1201 1202 (void) strcpy(cs->oem, cis_getstr(tp)); 1203 1204 if (GET_LEN(tp) > 0) 1205 (void) strcpy(cs->info, cis_getstr(tp)); 1206 else 1207 (void) strcpy(cs->info, "(no info)"); 1208 } 1209 1210 return (CISTPLF_NOERROR); 1211 } 1212 1213 /* 1214 * cistpl_jedec_handler - handler for JEDEC C and JEDEC A tuples 1215 * 1216 * void *arg - points to a XXX where the information is stuffed into 1217 */ 1218 uint32_t 1219 cistpl_jedec_handler(cistpl_callout_t *co, cistpl_t *tp, 1220 uint32_t flags, void *arg) 1221 { 1222 /* 1223 * nothing special about our flags, so just call the 1224 * generic handler for this 1225 */ 1226 if (flags & HANDTPL_SET_FLAGS) 1227 return (cis_no_tuple_handler(co, tp, flags, arg)); 1228 1229 /* 1230 * We don't currently validate this tuple. This call will 1231 * always set tp->flags |= CISTPLF_VALID. 1232 */ 1233 if (flags & HANDTPL_COPY_DONE) 1234 return (cis_no_tuple_handler(co, tp, flags, arg)); 1235 1236 if (flags & HANDTPL_PARSE_LTUPLE) { 1237 int nid; 1238 cistpl_jedec_t *cs = (cistpl_jedec_t *)arg; 1239 1240 RESET_TP(tp); 1241 1242 for (nid = 0; GET_LEN(tp) > 0 && 1243 nid < CISTPL_JEDEC_MAX_IDENTIFIERS && 1244 LOOK_BYTE(tp) != 0xFF; nid++) { 1245 cs->jid[nid].id = GET_BYTE(tp); 1246 cs->jid[nid].info = GET_BYTE(tp); 1247 } 1248 cs->nid = nid; 1249 } 1250 1251 return (CISTPLF_NOERROR); 1252 } 1253 1254 /* 1255 * cistpl_format_handler - handler for the CISTPL_FORMAT and 1256 * CISTPL_FORMAT_A tuples 1257 */ 1258 uint32_t 1259 cistpl_format_handler(cistpl_callout_t *co, cistpl_t *tp, 1260 uint32_t flags, void *arg) 1261 { 1262 /* 1263 * nothing special about our flags, so just call the 1264 * generic handler for this 1265 */ 1266 if (flags & HANDTPL_SET_FLAGS) 1267 return (cis_no_tuple_handler(co, tp, flags, arg)); 1268 1269 /* 1270 * We don't currently validate this tuple. This call will 1271 * always set tp->flags |= CISTPLF_VALID. 1272 */ 1273 if (flags & HANDTPL_COPY_DONE) 1274 return (cis_no_tuple_handler(co, tp, flags, arg)); 1275 1276 if (flags & HANDTPL_PARSE_LTUPLE) { 1277 cistpl_format_t *cs = (cistpl_format_t *)arg; 1278 1279 RESET_TP(tp); 1280 1281 cs->type = GET_BYTE(tp); 1282 cs->edc_length = LOOK_BYTE(tp) & EDC_LENGTH_MASK; 1283 cs->edc_type = ((uint32_t)GET_BYTE(tp) >> EDC_TYPE_SHIFT) & 1284 EDC_TYPE_MASK; 1285 cs->offset = GET_LONG(tp); 1286 cs->nbytes = GET_LONG(tp); 1287 1288 switch (cs->type) { 1289 case TPLFMTTYPE_DISK: 1290 cs->dev.disk.bksize = GET_SHORT(tp); 1291 cs->dev.disk.nblocks = GET_LONG(tp); 1292 cs->dev.disk.edcloc = GET_LONG(tp); 1293 break; 1294 1295 case TPLFMTTYPE_MEM: 1296 cs->dev.mem.flags = GET_BYTE(tp); 1297 cs->dev.mem.reserved = GET_BYTE(tp); 1298 cs->dev.mem.address = (caddr_t)(uintptr_t)GET_LONG(tp); 1299 cs->dev.disk.edcloc = GET_LONG(tp); 1300 break; 1301 default: 1302 /* don't know about any other type */ 1303 break; 1304 } 1305 } 1306 1307 return (CISTPLF_NOERROR); 1308 } 1309 1310 /* 1311 * cistpl_geometry_handler - handler for the CISTPL_GEOMETRY tuple 1312 * 1313 * void *arg - points to a XXX where the information is stuffed into 1314 */ 1315 uint32_t 1316 cistpl_geometry_handler(cistpl_callout_t *co, cistpl_t *tp, uint32_t flags, 1317 void *arg) 1318 { 1319 /* 1320 * nothing special about our flags, so just call the 1321 * generic handler for this 1322 */ 1323 if (flags & HANDTPL_SET_FLAGS) 1324 return (cis_no_tuple_handler(co, tp, flags, arg)); 1325 1326 /* 1327 * We don't currently validate this tuple. This call will 1328 * always set tp->flags |= CISTPLF_VALID. 1329 */ 1330 if (flags & HANDTPL_COPY_DONE) 1331 return (cis_no_tuple_handler(co, tp, flags, arg)); 1332 1333 if (flags & HANDTPL_PARSE_LTUPLE) { 1334 cistpl_geometry_t *cs = (cistpl_geometry_t *)arg; 1335 1336 RESET_TP(tp); 1337 cs->spt = GET_BYTE(tp); 1338 cs->tpc = GET_BYTE(tp); 1339 cs->ncyl = GET_SHORT(tp); 1340 } 1341 return (CISTPLF_NOERROR); 1342 } 1343 1344 /* 1345 * cistpl_byteorder_handler - handler for the CISTPL_BYTEORDER tuple 1346 * 1347 * void *arg - points to a XXX where the information is stuffed into 1348 */ 1349 uint32_t 1350 cistpl_byteorder_handler(cistpl_callout_t *co, cistpl_t *tp, uint32_t flags, 1351 void *arg) 1352 { 1353 /* 1354 * nothing special about our flags, so just call the 1355 * generic handler for this 1356 */ 1357 if (flags & HANDTPL_SET_FLAGS) 1358 return (cis_no_tuple_handler(co, tp, flags, arg)); 1359 1360 /* 1361 * We don't currently validate this tuple. This call will 1362 * always set tp->flags |= CISTPLF_VALID. 1363 */ 1364 if (flags & HANDTPL_COPY_DONE) 1365 return (cis_no_tuple_handler(co, tp, flags, arg)); 1366 1367 if (flags & HANDTPL_PARSE_LTUPLE) { 1368 cistpl_byteorder_t *cs = (cistpl_byteorder_t *)arg; 1369 1370 RESET_TP(tp); 1371 cs->order = GET_BYTE(tp); 1372 cs->map = GET_BYTE(tp); 1373 } 1374 return (CISTPLF_NOERROR); 1375 } 1376 1377 /* 1378 * cistpl_date_handler - handler for CISTPL_DATE card format tuple 1379 * 1380 * void *arg - points to a cistpl_date_t * where the 1381 * information is stuffed into 1382 */ 1383 uint32_t 1384 cistpl_date_handler(cistpl_callout_t *co, cistpl_t *tp, 1385 uint32_t flags, void *arg) 1386 { 1387 /* 1388 * nothing special about our flags, so just call the 1389 * generic handler for this 1390 */ 1391 if (flags & HANDTPL_SET_FLAGS) 1392 return (cis_no_tuple_handler(co, tp, flags, arg)); 1393 1394 /* 1395 * We don't currently validate this tuple. This call will 1396 * always set tp->flags |= CISTPLF_VALID. 1397 */ 1398 if (flags & HANDTPL_COPY_DONE) 1399 return (cis_no_tuple_handler(co, tp, flags, arg)); 1400 1401 if (flags & HANDTPL_PARSE_LTUPLE) { 1402 cistpl_date_t *cs = (cistpl_date_t *)arg; 1403 1404 RESET_TP(tp); 1405 cs->time = GET_SHORT(tp); 1406 cs->day = GET_SHORT(tp); 1407 } 1408 return (CISTPLF_NOERROR); 1409 } 1410 1411 /* 1412 * cistpl_battery_handler - handler for CISTPL_BATTERY battery replacement 1413 * date tuple 1414 * 1415 * void *arg - points to a cistpl_battery_t * where the 1416 * information is stuffed into 1417 */ 1418 uint32_t 1419 cistpl_battery_handler(cistpl_callout_t *co, cistpl_t *tp, 1420 uint32_t flags, void *arg) 1421 { 1422 /* 1423 * nothing special about our flags, so just call the 1424 * generic handler for this 1425 */ 1426 if (flags & HANDTPL_SET_FLAGS) 1427 return (cis_no_tuple_handler(co, tp, flags, arg)); 1428 1429 /* 1430 * We don't currently validate this tuple. This call will 1431 * always set tp->flags |= CISTPLF_VALID. 1432 */ 1433 if (flags & HANDTPL_COPY_DONE) 1434 return (cis_no_tuple_handler(co, tp, flags, arg)); 1435 1436 if (flags & HANDTPL_PARSE_LTUPLE) { 1437 cistpl_battery_t *cs = (cistpl_battery_t *)arg; 1438 1439 RESET_TP(tp); 1440 cs->rday = GET_SHORT(tp); 1441 cs->xday = GET_SHORT(tp); 1442 } 1443 return (CISTPLF_NOERROR); 1444 } 1445 1446 /* 1447 * cistpl_org_handler - handler for CISTPL_ORG data organization tuple 1448 * 1449 * void *arg - points to a cistpl_org_t * where the 1450 * information is stuffed into 1451 */ 1452 uint32_t 1453 cistpl_org_handler(cistpl_callout_t *co, cistpl_t *tp, 1454 uint32_t flags, void *arg) 1455 { 1456 /* 1457 * nothing special about our flags, so just call the 1458 * generic handler for this 1459 */ 1460 if (flags & HANDTPL_SET_FLAGS) 1461 return (cis_no_tuple_handler(co, tp, flags, arg)); 1462 1463 /* 1464 * We don't currently validate this tuple. This call will 1465 * always set tp->flags |= CISTPLF_VALID. 1466 */ 1467 if (flags & HANDTPL_COPY_DONE) 1468 return (cis_no_tuple_handler(co, tp, flags, arg)); 1469 1470 if (flags & HANDTPL_PARSE_LTUPLE) { 1471 cistpl_org_t *cs = (cistpl_org_t *)arg; 1472 1473 RESET_TP(tp); 1474 cs->type = GET_BYTE(tp); 1475 1476 (void) strcpy(cs->desc, cis_getstr(tp)); 1477 } 1478 1479 return (CISTPLF_NOERROR); 1480 } 1481 1482 1483 /* 1484 * cistpl_manfid_handler - handler for CISTPL_MANFID, the manufacturer ID tuple 1485 * 1486 * void *arg - points to a XXX where the information is stuffed into 1487 */ 1488 uint32_t 1489 cistpl_manfid_handler(cistpl_callout_t *co, cistpl_t *tp, 1490 uint32_t flags, void *arg) 1491 { 1492 /* 1493 * nothing special about our flags, so just call the 1494 * generic handler for this 1495 */ 1496 if (flags & HANDTPL_SET_FLAGS) 1497 return (cis_no_tuple_handler(co, tp, flags, arg)); 1498 1499 /* 1500 * We don't currently validate this tuple. This call will 1501 * always set tp->flags |= CISTPLF_VALID. 1502 */ 1503 if (flags & HANDTPL_COPY_DONE) 1504 return (cis_no_tuple_handler(co, tp, flags, arg)); 1505 1506 if (flags & HANDTPL_PARSE_LTUPLE) { 1507 cistpl_manfid_t *cs = (cistpl_manfid_t *)arg; 1508 1509 RESET_TP(tp); 1510 cs->manf = GET_SHORT(tp); 1511 cs->card = GET_SHORT(tp); 1512 } 1513 return (CISTPLF_NOERROR); 1514 } 1515 1516 /* 1517 * cistpl_funcid_handler - handler for CISTPL_FUNCID 1518 * 1519 * void *arg - points to a XXX where the information is stuffed into 1520 */ 1521 uint32_t 1522 cistpl_funcid_handler(cistpl_callout_t *co, cistpl_t *tp, 1523 uint32_t flags, void *arg) 1524 { 1525 /* 1526 * nothing special about our flags, so just call the 1527 * generic handler for this 1528 */ 1529 if (flags & HANDTPL_SET_FLAGS) 1530 return (cis_no_tuple_handler(co, tp, flags, arg)); 1531 1532 /* 1533 * We don't currently validate this tuple. This call will 1534 * always set tp->flags |= CISTPLF_VALID. 1535 */ 1536 if (flags & HANDTPL_COPY_DONE) 1537 return (cis_no_tuple_handler(co, tp, flags, arg)); 1538 1539 if (flags & HANDTPL_PARSE_LTUPLE) { 1540 cistpl_funcid_t *cs = (cistpl_funcid_t *)arg; 1541 1542 RESET_TP(tp); 1543 1544 cs->function = GET_BYTE(tp); 1545 cs->sysinit = GET_BYTE(tp); 1546 } 1547 return (CISTPLF_NOERROR); 1548 } 1549 1550 1551 /* 1552 * cistpl_funce_serial_handler - handler for the CISTPL_FUNCE/SERIAL tuple 1553 * 1554 * void *arg - points to a XXX where the information is stuffed into 1555 */ 1556 uint32_t 1557 cistpl_funce_serial_handler(cistpl_callout_t *co, cistpl_t *tp, 1558 uint32_t flags, void *arg) 1559 { 1560 int subfunction; 1561 1562 /* 1563 * nothing special about our flags, so just call the 1564 * generic handler for this 1565 */ 1566 if (flags & HANDTPL_SET_FLAGS) 1567 return (cis_no_tuple_handler(co, tp, flags, arg)); 1568 1569 /* 1570 * We don't currently validate this tuple. This call will 1571 * always set tp->flags |= CISTPLF_VALID. 1572 */ 1573 if (flags & HANDTPL_COPY_DONE) 1574 return (cis_no_tuple_handler(co, tp, flags, arg)); 1575 1576 if (flags & HANDTPL_PARSE_LTUPLE) { 1577 cistpl_funce_t *cs = (cistpl_funce_t *)arg; 1578 1579 RESET_TP(tp); 1580 1581 cs->function = TPLFUNC_SERIAL; 1582 cs->subfunction = subfunction = GET_BYTE(tp); 1583 switch (subfunction & 0xF) { 1584 case TPLFE_SUB_SERIAL: 1585 case TPLFE_CAP_SERIAL_DATA: 1586 case TPLFE_CAP_SERIAL_FAX: 1587 case TPLFE_CAP_SERIAL_VOICE: 1588 cs->data.serial.ua = GET_BYTE(tp); 1589 cs->data.serial.uc = GET_SHORT(tp); 1590 break; 1591 case TPLFE_SUB_MODEM_COMMON: 1592 case TPLFE_CAP_MODEM_DATA: 1593 case TPLFE_CAP_MODEM_FAX: 1594 case TPLFE_CAP_MODEM_VOICE: 1595 cs->data.modem.fc = GET_BYTE(tp); 1596 cs->data.modem.cb = (GET_BYTE(tp) + 1) * 4; 1597 cs->data.modem.eb = GET_INT24(tp); 1598 cs->data.modem.tb = GET_INT24(tp); 1599 break; 1600 case TPLFE_SUB_MODEM_DATA: 1601 cs->data.data_modem.ud = GET_BE_SHORT(tp) * 75; 1602 cs->data.data_modem.ms = GET_SHORT(tp); 1603 cs->data.data_modem.em = GET_BYTE(tp); 1604 cs->data.data_modem.dc = GET_BYTE(tp); 1605 cs->data.data_modem.cm = GET_BYTE(tp); 1606 cs->data.data_modem.ex = GET_BYTE(tp); 1607 cs->data.data_modem.dy = GET_BYTE(tp); 1608 cs->data.data_modem.ef = GET_BYTE(tp); 1609 for (cs->data.data_modem.ncd = 0; 1610 GET_LEN(tp) > 0 && cs->data.data_modem.ncd < 16; 1611 cs->data.data_modem.ncd++) 1612 if (LOOK_BYTE(tp) != 255) { 1613 cs->data.data_modem.cd[ 1614 cs->data.data_modem.ncd] = 1615 GET_BYTE(tp); 1616 } else { 1617 GET_BYTE(tp); 1618 break; 1619 } 1620 break; 1621 case TPLFE_SUB_MODEM_FAX: 1622 cs->data.fax.uf = GET_BE_SHORT(tp) * 75; 1623 cs->data.fax.fm = GET_BYTE(tp); 1624 cs->data.fax.fy = GET_BYTE(tp); 1625 cs->data.fax.fs = GET_SHORT(tp); 1626 for (cs->data.fax.ncf = 0; 1627 GET_LEN(tp) > 0 && cs->data.fax.ncf < 16; 1628 cs->data.fax.ncf++) 1629 if (LOOK_BYTE(tp) != 255) { 1630 cs->data.fax.cf[cs->data.fax.ncf] = 1631 GET_BYTE(tp); 1632 } else { 1633 GET_BYTE(tp); 1634 break; 1635 } 1636 break; 1637 case TPLFE_SUB_VOICE: 1638 cs->data.voice.uv = GET_BE_SHORT(tp) * 75; 1639 for (cs->data.voice.nsr = 0; LOOK_BYTE(tp) != 0 && 1640 GET_LEN(tp) >= 2; 1641 cs->data.voice.nsr++) { 1642 cs->data.voice.sr[cs->data.voice.nsr] = 1643 GET_BYTE(tp) * 1000; 1644 cs->data.voice.sr[cs->data.voice.nsr] += 1645 GET_BYTE(tp) * 100; 1646 } 1647 for (cs->data.voice.nss = 0; LOOK_BYTE(tp) != 0 && 1648 GET_LEN(tp) >= 2; 1649 cs->data.voice.nss++) { 1650 cs->data.voice.ss[cs->data.voice.nss] = 1651 GET_BYTE(tp) * 10; 1652 cs->data.voice.ss[cs->data.voice.nss] += 1653 GET_BYTE(tp); 1654 } 1655 for (cs->data.voice.nsc = 0; LOOK_BYTE(tp) != 0 && 1656 GET_LEN(tp) >= 1; 1657 cs->data.voice.nsc++) { 1658 cs->data.voice.sc[cs->data.voice.nsc] = 1659 GET_BYTE(tp); 1660 } 1661 break; 1662 default: 1663 break; 1664 } 1665 } 1666 return (CISTPLF_NOERROR); 1667 } 1668 1669 /* 1670 * cistpl_funce_lan_handler - handler for the CISTPL_FUNCE/LAN tuple 1671 * 1672 * void *arg - points to a XXX where the information is stuffed into 1673 */ 1674 uint32_t 1675 cistpl_funce_lan_handler(cistpl_callout_t *co, cistpl_t *tp, uint32_t flags, 1676 void *arg) 1677 { 1678 int subfunction; 1679 1680 /* 1681 * nothing special about our flags, so just call the 1682 * generic handler for this 1683 */ 1684 if (flags & HANDTPL_SET_FLAGS) 1685 return (cis_no_tuple_handler(co, tp, flags, arg)); 1686 1687 /* 1688 * We don't currently validate this tuple. This call will 1689 * always set tp->flags |= CISTPLF_VALID. 1690 */ 1691 if (flags & HANDTPL_COPY_DONE) 1692 return (cis_no_tuple_handler(co, tp, flags, arg)); 1693 1694 if (flags & HANDTPL_PARSE_LTUPLE) { 1695 int i; 1696 cistpl_funce_t *cs = (cistpl_funce_t *)arg; 1697 1698 RESET_TP(tp); 1699 1700 cs->function = TPLFUNC_LAN; 1701 cs->subfunction = subfunction = GET_BYTE(tp); 1702 1703 switch (subfunction) { 1704 case TPLFE_NETWORK_INFO: 1705 cs->data.lan.tech = GET_BYTE(tp); 1706 cs->data.lan.speed = GET_BYTE(tp); 1707 i = GET_BYTE(tp); 1708 if (i < 24) { 1709 cs->data.lan.speed <<= i; 1710 } else { 1711 /* 1712 * if speed is too large a value 1713 * to hold in a uint32 flag it and 1714 * store as [mantissa][exponent] 1715 * in least significant 16 bits 1716 */ 1717 cs->data.lan.speed = 0x80000000 | 1718 (cs->data.lan.speed << 8) | i; 1719 } 1720 cs->data.lan.media = GET_BYTE(tp); 1721 cs->data.lan.con = GET_BYTE(tp); 1722 cs->data.lan.id_sz = GET_BYTE(tp); 1723 if (cs->data.lan.id_sz <= 16) { 1724 for (i = 0; i < cs->data.lan.id_sz; i++) 1725 cs->data.lan.id[i] = GET_BYTE(tp); 1726 } 1727 break; 1728 default: 1729 /* unknown LAN tuple type */ 1730 return (CISTPLF_UNKNOWN); 1731 } 1732 } 1733 return (CISTPLF_NOERROR); 1734 } 1735 1736 /* 1737 * cistpl_linktarget_handler - handler for CISTPL_LINKTARGET tuple 1738 * 1739 * void *arg - points to a cistpl_linktarget_t * where the 1740 * information is stuffed into 1741 * 1742 * If HANDTPL_COPY_DONE is set, we just validate the tuple but 1743 * do not return any values. 1744 * If HANDTPL_PARSE_LTUPLE is set, we validate the tuple and 1745 * return the parsed tuple data if the tuple is valid. 1746 * 1747 * If the tuple link field is invalid, the CISTPLF_LINK_INVALID flag 1748 * will be set in the tp->flags field and HANDTPL_ERROR 1749 * will be returned. 1750 * 1751 * If the tuple data body is invalid, the CISTPLF_PARAMS_INVALID flag 1752 * will be set in the tp->flags field and HANDTPL_ERROR 1753 * will be returned. 1754 * 1755 * The tuple is considered invalid if it's link field is less than 1756 * MIN_LINKTARGET_LENGTH or if the data body of the tuple 1757 * does not contain the pattern CISTPL_LINKTARGET_MAGIC. 1758 * 1759 * XXX At some point we should revisit this to see if we can call 1760 * cis_validate_longlink_acm instead of doing the validation 1761 * in both places. 1762 */ 1763 uint32_t 1764 cistpl_linktarget_handler(cistpl_callout_t *co, cistpl_t *tp, uint32_t flags, 1765 void *arg) 1766 { 1767 /* 1768 * nothing special about our flags, so just call the 1769 * generic handler for this 1770 */ 1771 if (flags & HANDTPL_SET_FLAGS) 1772 return (cis_no_tuple_handler(co, tp, flags, arg)); 1773 1774 /* 1775 * Validate the tuple for both the HANDTPL_COPY_DONE case and 1776 * the HANDTPL_PARSE_LTUPLE case. Only return data in 1777 * the HANDTPL_PARSE_LTUPLE case. 1778 */ 1779 if (flags & (HANDTPL_COPY_DONE | HANDTPL_PARSE_LTUPLE)) { 1780 uchar_t *cp; 1781 cisdata_t tl; 1782 1783 if ((tl = tp->len) >= (cisdata_t)MIN_LINKTARGET_LENGTH) { 1784 cisdata_t *ltm = (cisdata_t *)CISTPL_LINKTARGET_MAGIC; 1785 int i; 1786 1787 RESET_TP(tp); 1788 1789 /* 1790 * Save the start address of this string in case 1791 * the tuple turns out to be OK since we 1792 * need to pass this address to the caller. 1793 */ 1794 cp = GET_BYTE_ADDR(tp); 1795 1796 /* 1797 * Check each byte of the tuple body to see if it 1798 * matches what should be in a valid tuple. 1799 * Note that we can't assume that this magic 1800 * pattern is a string and we also only need 1801 * to be sure that MIN_LINKTARGET_LENGTH bytes 1802 * match; all bytes following this magic number 1803 * in this tuple are ignored. 1804 */ 1805 for (i = 0; i < MIN_LINKTARGET_LENGTH; i++) { 1806 if (GET_BYTE(tp) != *ltm++) { 1807 tp->flags |= CISTPLF_PARAMS_INVALID; 1808 return (HANDTPL_ERROR); 1809 } 1810 } /* MIN_LINKTARGET_LENGTH */ 1811 1812 /* 1813 * This tuple is valid. 1814 */ 1815 if (flags & HANDTPL_COPY_DONE) 1816 tp->flags |= CISTPLF_VALID; 1817 1818 /* 1819 * If we're also parsing this tuple, then 1820 * setup the return values. 1821 */ 1822 if (flags & HANDTPL_PARSE_LTUPLE) { 1823 cistpl_linktarget_t *cs = 1824 (cistpl_linktarget_t *)arg; 1825 1826 cs->length = tl; 1827 (void) strncpy(cs->tpltg_tag, (char *)cp, 1828 cs->length); 1829 cs->tpltg_tag[cs->length] = NULL; 1830 1831 } /* HANDTPL_PARSE_LTUPLE */ 1832 1833 } else { 1834 1835 tp->flags |= CISTPLF_LINK_INVALID; 1836 return (HANDTPL_ERROR); 1837 1838 } /* CISTPL_LINKTARGET */ 1839 1840 } /* (HANDTPL_COPY_DONE | HANDTPL_PARSE_LTUPLE) */ 1841 1842 return (CISTPLF_NOERROR); 1843 } 1844 1845 /* 1846 * cistpl_longlink_ac_handler - handler for CISTPL_LONGLINK_A and 1847 * CISTPL_LONGLINK_C tuples 1848 * 1849 * void *arg - points to a cistpl_longlink_ac_t * where the 1850 * information is stuffed into 1851 * 1852 * If the passed in tuple is CISTPL_LONGLINK_A the CISTPL_LONGLINK_AC_AM 1853 * flag in cistpl_longlink_ac_t->flags is set. 1854 * If the passed in tuple is CISTPL_LONGLINK_C the CISTPL_LONGLINK_AC_CM 1855 * flag in cistpl_longlink_ac_t->flags is set. 1856 * 1857 * If HANDTPL_COPY_DONE is set, we just validate the tuple but 1858 * do not return any values. 1859 * If HANDTPL_PARSE_LTUPLE is set, we validate the tuple and 1860 * return the parsed tuple data if the tuple is valid. 1861 * 1862 * If the tuple link field is invalid, the CISTPLF_LINK_INVALID flag 1863 * will be set in the tp->flags field and HANDTPL_ERROR 1864 * will be returned. 1865 * 1866 * The tuple is considered invalid if it's link field is less than 1867 * MIN_LONGLINK_AC_LENGTH. 1868 */ 1869 uint32_t 1870 cistpl_longlink_ac_handler(cistpl_callout_t *co, cistpl_t *tp, uint32_t flags, 1871 void *arg) 1872 { 1873 /* 1874 * nothing special about our flags, so just call the 1875 * generic handler for this 1876 */ 1877 if (flags & HANDTPL_SET_FLAGS) 1878 return (cis_no_tuple_handler(co, tp, flags, arg)); 1879 1880 /* 1881 * Validate the tuple for both the HANDTPL_COPY_DONE case and 1882 * the HANDTPL_PARSE_LTUPLE case. Only return data in 1883 * the HANDTPL_PARSE_LTUPLE case. 1884 */ 1885 if (flags & (HANDTPL_COPY_DONE | HANDTPL_PARSE_LTUPLE)) { 1886 1887 if (tp->len >= (cisdata_t)MIN_LONGLINK_AC_LENGTH) { 1888 1889 /* 1890 * This tuple is valid. 1891 */ 1892 if (flags & HANDTPL_COPY_DONE) 1893 tp->flags |= CISTPLF_VALID; 1894 1895 if (flags & HANDTPL_PARSE_LTUPLE) { 1896 cistpl_longlink_ac_t *cs = 1897 (cistpl_longlink_ac_t *)arg; 1898 1899 switch (tp->type) { 1900 case CISTPL_LONGLINK_A: 1901 cs->flags = CISTPL_LONGLINK_AC_AM; 1902 break; 1903 1904 case CISTPL_LONGLINK_C: 1905 cs->flags = CISTPL_LONGLINK_AC_CM; 1906 break; 1907 default: 1908 break; 1909 } /* switch */ 1910 1911 RESET_TP(tp); 1912 1913 cs->tpll_addr = GET_LONG(tp); 1914 1915 } /* HANDTPL_PARSE_LTUPLE */ 1916 1917 } else { 1918 tp->flags |= CISTPLF_LINK_INVALID; 1919 return (HANDTPL_ERROR); 1920 } /* MIN_LONGLINK_AC_LENGTH */ 1921 1922 } /* (HANDTPL_COPY_DONE | HANDTPL_PARSE_LTUPLE) */ 1923 1924 return (CISTPLF_NOERROR); 1925 } 1926 1927 /* 1928 * cistpl_longlink_mfc_handler - handler for CISTPL_LONGLINK_MFC tuples 1929 * 1930 * void *arg - points to a cistpl_longlink_mfc_t * where the 1931 * information is stuffed into 1932 * 1933 * If HANDTPL_COPY_DONE is set, we just validate the tuple but 1934 * do not return any values. 1935 * If HANDTPL_PARSE_LTUPLE is set, we validate the tuple and 1936 * return the parsed tuple data if the tuple is valid. 1937 * 1938 * If the tuple link field is invalid, the CISTPLF_LINK_INVALID flag 1939 * will be set in the tp->flags field and HANDTPL_ERROR 1940 * will be returned. 1941 * 1942 * If the number of register sets is invalid, the CISTPLF_PARAMS_INVALID 1943 * flag be set in the tp->flags field and HANDTPL_ERROR will be 1944 * returned. 1945 * 1946 * The tuple is considered invalid if it's link field is less than 1947 * MIN_LONGLINK_MFC_LENGTH or if the number of register sets 1948 * is not in the range [MIN_LONGLINK_MFC_NREGS..CIS_MAX_FUNCTIONS] 1949 */ 1950 uint32_t 1951 cistpl_longlink_mfc_handler(cistpl_callout_t *co, cistpl_t *tp, 1952 uint32_t flags, void *arg) 1953 { 1954 /* 1955 * nothing special about our flags, so just call the 1956 * generic handler for this 1957 */ 1958 if (flags & HANDTPL_SET_FLAGS) 1959 return (cis_no_tuple_handler(co, tp, flags, arg)); 1960 1961 /* 1962 * Validate the tuple for both the HANDTPL_COPY_DONE case and 1963 * the HANDTPL_PARSE_LTUPLE case. Only return data in 1964 * the HANDTPL_PARSE_LTUPLE case. 1965 */ 1966 if (flags & (HANDTPL_COPY_DONE | HANDTPL_PARSE_LTUPLE)) { 1967 1968 if (tp->len >= (cisdata_t)MIN_LONGLINK_MFC_LENGTH) { 1969 1970 /* 1971 * This tuple is valid. 1972 */ 1973 if (flags & HANDTPL_COPY_DONE) 1974 tp->flags |= CISTPLF_VALID; 1975 1976 if (flags & HANDTPL_PARSE_LTUPLE) { 1977 cistpl_longlink_mfc_t *cs = 1978 (cistpl_longlink_mfc_t *)arg; 1979 int fn; 1980 1981 RESET_TP(tp); 1982 1983 /* 1984 * Get the number of register sets described 1985 * by this tuple. The number of register 1986 * sets must be greter than or equal to 1987 * MIN_LONGLINK_MFC_NREGS and less than 1988 * CIS_MAX_FUNCTIONS. 1989 * Note that the number of functions is equal 1990 * to the number of register sets. 1991 */ 1992 cs->nregs = GET_BYTE(tp); 1993 cs->nfuncs = cs->nregs; 1994 1995 if ((cs->nregs < MIN_LONGLINK_MFC_NREGS) || 1996 (cs->nregs > CIS_MAX_FUNCTIONS)) { 1997 tp->flags |= CISTPLF_PARAMS_INVALID; 1998 return (HANDTPL_ERROR); 1999 } 2000 2001 /* 2002 * Cycle through each function and setup 2003 * the appropriate parameter values. 2004 */ 2005 for (fn = 0; fn < cs->nregs; fn++) { 2006 cs->function[fn].tas = GET_BYTE(tp); 2007 cs->function[fn].addr = GET_LONG(tp); 2008 } /* for (fn) */ 2009 2010 } /* HANDTPL_PARSE_LTUPLE */ 2011 2012 } else { 2013 tp->flags |= CISTPLF_LINK_INVALID; 2014 return (HANDTPL_ERROR); 2015 } /* MIN_LONGLINK_MFC_LENGTH */ 2016 2017 } /* (HANDTPL_COPY_DONE | HANDTPL_PARSE_LTUPLE) */ 2018 2019 return (CISTPLF_NOERROR); 2020 } 2021 2022 /* 2023 * cis_validate_longlink_acm - Validates the secondary tuple chain pointed 2024 * to by cisptr and specified by a previous 2025 * CISTPL_LONGLINK_A, CISTPL_LONGLINK_C or 2026 * CISTPL_LONGLINK_MFC tuple. 2027 * 2028 * cisptr->offset must be the offset to the first byte in the secondary 2029 * tuple chain to validate 2030 * cisptr->flags must be setup to specify the correct address space 2031 * 2032 * The cisptr->offset member is not updated after this function returns. 2033 * 2034 * BAD_CIS_ADDR is returned is the raw CIS data cound not be read. 2035 * HANDTPL_ERROR is returned if the secondary tuple chain does not 2036 * contain a valid CISTPL_LINKTARGET tuple. 2037 */ 2038 uint32_t 2039 cis_validate_longlink_acm(cisptr_t *cisptr) 2040 { 2041 uchar_t cb[MIN_LINKTARGET_LENGTH + LINKTARGET_AC_HEADER_LENGTH]; 2042 cisptr_t t_cisptr, *cpt; 2043 int tl; 2044 2045 /* 2046 * Since the NEXT_CIS_ADDR macro increments the cisptr_t->offset 2047 * member, make a local copy of the cisptr and use the local 2048 * copy to read data from the card. 2049 */ 2050 cpt = &t_cisptr; 2051 bcopy((caddr_t)cisptr, (caddr_t)cpt, sizeof (cisptr_t)); 2052 2053 for (tl = 0; tl < MIN_LINKTARGET_LENGTH + 2054 LINKTARGET_AC_HEADER_LENGTH; tl++) { 2055 2056 cb[tl] = GET_CIS_DATA(cpt); 2057 if (!NEXT_CIS_ADDR(cpt)) 2058 return ((uint32_t)BAD_CIS_ADDR); 2059 2060 } /* for */ 2061 2062 if ((cb[0] == CISTPL_LINKTARGET) && (cb[1] >= MIN_LINKTARGET_LENGTH)) { 2063 cisdata_t *ltm = (cisdata_t *)CISTPL_LINKTARGET_MAGIC; 2064 2065 for (tl = 0; tl < MIN_LINKTARGET_LENGTH; tl++, ltm++) { 2066 if (cb[tl + LINKTARGET_AC_HEADER_LENGTH] != *ltm) 2067 return (HANDTPL_ERROR); 2068 } 2069 return (CISTPLF_NOERROR); 2070 2071 } /* if */ 2072 2073 return (HANDTPL_ERROR); 2074 } 2075 2076 /* 2077 * cis_getstr (tp) 2078 * we want the address of the first character returned 2079 * but need to skip past the string in the cistpl_t structure 2080 */ 2081 char * 2082 cis_getstr(cistpl_t *tp) 2083 { 2084 uchar_t *cp, *cpp; 2085 uchar_t x; 2086 2087 cp = tp->read.byte; 2088 cpp = cp; 2089 2090 while ((x = LOOK_BYTE(tp)) != 0 && x != 0xff) { 2091 x = GET_BYTE(tp); 2092 } 2093 2094 (void) GET_BYTE(tp); /* get past that last byte */ 2095 2096 while ((*cpp != 0) && (*cpp != 0xff)) 2097 cpp++; 2098 2099 *cpp = NULL; 2100 2101 return ((char *)cp); 2102 } 2103 2104 /* 2105 * cis_return_name - returns name of tuple 2106 * 2107 * calling: co - pointer to cistpl_callout_t entry that contains 2108 * tuple name to return 2109 * gtn - pointer to cistpl_get_tuple_name_t to return 2110 * name into 2111 */ 2112 static void 2113 cis_return_name(cistpl_callout_t *co, cistpl_get_tuple_name_t *gtn) 2114 { 2115 (void) strncpy(gtn->name, co->text, CIS_MAX_TUPLE_NAME_LEN); 2116 gtn->name[CIS_MAX_TUPLE_NAME_LEN - 1] = NULL; 2117 } 2118 2119 /* 2120 * cis_malloc/cis_free 2121 * wrappers around kmem_alloc()/kmem_free() that 2122 * provide malloc/free style usage 2123 */ 2124 2125 caddr_t 2126 cis_malloc(size_t len) 2127 { 2128 caddr_t addr; 2129 2130 addr = kmem_zalloc(len + sizeof (size_t), KM_SLEEP); 2131 *(size_t *)addr = len + sizeof (size_t); 2132 addr += sizeof (size_t); 2133 return (addr); 2134 } 2135 2136 void 2137 cis_free(caddr_t addr) 2138 { 2139 size_t len; 2140 addr -= sizeof (size_t); 2141 len = *(size_t *)addr; 2142 kmem_free(addr, len); 2143 } 2144