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