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