xref: /onnv-gate/usr/src/uts/common/pcmcia/cis/cis_handlers.c (revision 1278:cccbfe741e06)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*1278Shx147065  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * This file contains the tuple handlers that are called by the CIS
310Sstevel@tonic-gate  *	parser.
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * XXX - how about a better explaination??
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <sys/systm.h>
380Sstevel@tonic-gate #include <sys/user.h>
390Sstevel@tonic-gate #include <sys/buf.h>
400Sstevel@tonic-gate #include <sys/file.h>
410Sstevel@tonic-gate #include <sys/uio.h>
420Sstevel@tonic-gate #include <sys/conf.h>
430Sstevel@tonic-gate #include <sys/stat.h>
440Sstevel@tonic-gate #include <sys/autoconf.h>
450Sstevel@tonic-gate #include <sys/vtoc.h>
460Sstevel@tonic-gate #include <sys/dkio.h>
470Sstevel@tonic-gate #include <sys/ddi.h>
480Sstevel@tonic-gate #include <sys/sunddi.h>
490Sstevel@tonic-gate #include <sys/debug.h>
500Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
510Sstevel@tonic-gate #include <sys/kstat.h>
520Sstevel@tonic-gate #include <sys/kmem.h>
530Sstevel@tonic-gate #include <sys/modctl.h>
540Sstevel@tonic-gate #include <sys/kobj.h>
550Sstevel@tonic-gate #include <sys/callb.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate #include <sys/pctypes.h>
580Sstevel@tonic-gate #include <pcmcia/sys/cs_types.h>
590Sstevel@tonic-gate #include <pcmcia/sys/cis.h>
600Sstevel@tonic-gate #include <pcmcia/sys/cis_handlers.h>
610Sstevel@tonic-gate #include <pcmcia/sys/cs.h>
620Sstevel@tonic-gate #include <pcmcia/sys/cs_priv.h>
630Sstevel@tonic-gate #include <pcmcia/sys/cis_protos.h>
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate  * Function prototypes
670Sstevel@tonic-gate  */
680Sstevel@tonic-gate static void cistpl_pd_parse(cistpl_t *, cistpl_cftable_entry_pwr_t *);
690Sstevel@tonic-gate static void cis_return_name(cistpl_callout_t *, cistpl_get_tuple_name_t *);
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*
72*1278Shx147065  * Fetch data functions.
73*1278Shx147065  */
74*1278Shx147065 uint16_t
cis_get_short(cistpl_t * tp)75*1278Shx147065 cis_get_short(cistpl_t *tp)
76*1278Shx147065 {
77*1278Shx147065 	uint16_t result;
78*1278Shx147065 
79*1278Shx147065 	if (tp->flags & CISTPLF_AM_SPACE) {
80*1278Shx147065 		result = GET_AM_BYTE(tp);
81*1278Shx147065 		result |= GET_AM_BYTE(tp) << 8;
82*1278Shx147065 	} else {
83*1278Shx147065 		result = GET_CM_BYTE(tp);
84*1278Shx147065 		result |= GET_CM_BYTE(tp) << 8;
85*1278Shx147065 	}
86*1278Shx147065 	return (result);
87*1278Shx147065 }
88*1278Shx147065 
89*1278Shx147065 uint16_t
cis_get_be_short(cistpl_t * tp)90*1278Shx147065 cis_get_be_short(cistpl_t *tp)
91*1278Shx147065 {
92*1278Shx147065 	uint16_t result;
93*1278Shx147065 
94*1278Shx147065 	if (tp->flags & CISTPLF_AM_SPACE) {
95*1278Shx147065 		result = GET_AM_BYTE(tp) << 8;
96*1278Shx147065 		result |= GET_AM_BYTE(tp);
97*1278Shx147065 	} else {
98*1278Shx147065 		result = GET_CM_BYTE(tp) << 8;
99*1278Shx147065 		result |= GET_CM_BYTE(tp);
100*1278Shx147065 	}
101*1278Shx147065 	return (result);
102*1278Shx147065 }
103*1278Shx147065 
104*1278Shx147065 uint32_t
cis_get_int24(cistpl_t * tp)105*1278Shx147065 cis_get_int24(cistpl_t *tp)
106*1278Shx147065 {
107*1278Shx147065 	uint32_t result = cis_get_short(tp);
108*1278Shx147065 
109*1278Shx147065 	result |= GET_BYTE(tp) << 16;
110*1278Shx147065 	return (result);
111*1278Shx147065 }
112*1278Shx147065 
113*1278Shx147065 uint32_t
cis_get_long(cistpl_t * tp)114*1278Shx147065 cis_get_long(cistpl_t *tp)
115*1278Shx147065 {
116*1278Shx147065 	uint32_t result = cis_get_short(tp);
117*1278Shx147065 
118*1278Shx147065 	result |= cis_get_short(tp) << 16;
119*1278Shx147065 	return (result);
120*1278Shx147065 }
121*1278Shx147065 
122*1278Shx147065 /*
1230Sstevel@tonic-gate  * cis_tuple_handler - call the handler for the tuple described by the
1240Sstevel@tonic-gate  *				tuple pointer
1250Sstevel@tonic-gate  *
1260Sstevel@tonic-gate  *	cistpl_callout_t *co - pointer to callout structure
1270Sstevel@tonic-gate  *				array to use to find this tuple
1280Sstevel@tonic-gate  *	cistpl_t *tp - pointer to a tuple structure
1290Sstevel@tonic-gate  *	int flags - action for the handler to perform
1300Sstevel@tonic-gate  * XXX - we need a description of the flags passed to the tuple handler
1310Sstevel@tonic-gate  *	void *arg - argument to pass on to tuple handler
1320Sstevel@tonic-gate  *
1330Sstevel@tonic-gate  * If the tuple is not recognized but is is a vendor-specific tuple, we
1340Sstevel@tonic-gate  *	set the CISTPLF_VENDOR_SPECIFIC flag in the tuple.
1350Sstevel@tonic-gate  *
1360Sstevel@tonic-gate  * We return CISTPLF_UNKNOWN if this is an unrecognized	tuple as well as
1370Sstevel@tonic-gate  *	set the CISTPLF_UNKNOWN flag in the tuple list structure.  Note
1380Sstevel@tonic-gate  *	that encountering an unknown tuple is not necessarily an error,
1390Sstevel@tonic-gate  *	so we don't set the HANDTPL_ERROR flag on the return code.  It
1400Sstevel@tonic-gate  *	is up to the caller to determine what an unrecognized tuple means.
1410Sstevel@tonic-gate  *
1420Sstevel@tonic-gate  * If this is a recognized tuple, the apropriate tuple handler is called and
1430Sstevel@tonic-gate  *	the return value from the handler is returned directly to the caller.
1440Sstevel@tonic-gate  *
1450Sstevel@tonic-gate  * The void *arg is optional, and it's meaning is dependent on the
1460Sstevel@tonic-gate  *	particular tuple handler called and the flags parameter.
1470Sstevel@tonic-gate  *
1480Sstevel@tonic-gate  * For the special case of HANDTPL_RETURN_NAME, we don't bother calling the
1490Sstevel@tonic-gate  *	tuple handler and just return the tuple name to the caller.
1500Sstevel@tonic-gate  */
1510Sstevel@tonic-gate uint32_t
cis_tuple_handler(cistpl_callout_t * co,cistpl_t * tp,uint32_t flags,void * arg,cisdata_t subtype)1520Sstevel@tonic-gate cis_tuple_handler(cistpl_callout_t *co, cistpl_t *tp, uint32_t flags,
1530Sstevel@tonic-gate 					void *arg, cisdata_t subtype)
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate 	/*
1560Sstevel@tonic-gate 	 * Check to see if this is a vendor-specific tuple.
1570Sstevel@tonic-gate 	 */
1580Sstevel@tonic-gate 	if (CISTPL_IS_VENDOR_SPECIFIC(tp->type))
1590Sstevel@tonic-gate 	    tp->flags |= CISTPLF_VENDOR_SPECIFIC;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	/*
1620Sstevel@tonic-gate 	 * Scan the callout list until we find the tuple passed to us, or we
1630Sstevel@tonic-gate 	 *	encounter a CISTPL_END in the callout list, which signals that
1640Sstevel@tonic-gate 	 *	there are no more tuples in the callout list.
1650Sstevel@tonic-gate 	 */
1660Sstevel@tonic-gate 	while (co->type != (cisdata_t)CISTPL_END) {
1670Sstevel@tonic-gate 	    if (co->type == tp->type &&
1680Sstevel@tonic-gate 		((tp->type != CISTPL_FUNCE) ||
1690Sstevel@tonic-gate 		    (tp->type == CISTPL_FUNCE && co->subtype == subtype))) {
1700Sstevel@tonic-gate 			tp->flags &= ~CISTPLF_UNKNOWN;
1710Sstevel@tonic-gate 			if (flags & HANDTPL_RETURN_NAME) {
1720Sstevel@tonic-gate 			    cis_return_name(co, (cistpl_get_tuple_name_t *)arg);
1730Sstevel@tonic-gate 			    return (CISTPLF_NOERROR);
1740Sstevel@tonic-gate 			} else {
1750Sstevel@tonic-gate 			    return ((*co->handler) (co, tp, flags, arg));
1760Sstevel@tonic-gate 			} /* HANDTPL_RETURN_NAME */
1770Sstevel@tonic-gate 	    } /* if */
1780Sstevel@tonic-gate 	    co++;
1790Sstevel@tonic-gate 	} /* while */
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	/*
1820Sstevel@tonic-gate 	 * If we didn't recognize the tuple and the caller wants the tuple
1830Sstevel@tonic-gate 	 *	name back, then return the "unknown tuple" string. At this
1840Sstevel@tonic-gate 	 *	point, "co" will be pointing to the last entry in the
1850Sstevel@tonic-gate 	 *	callout list. It's not an error to not recognize the tuple
1860Sstevel@tonic-gate 	 *	when the operation is HANDTPL_RETURN_NAME.
1870Sstevel@tonic-gate 	 */
1880Sstevel@tonic-gate 	if (flags & HANDTPL_RETURN_NAME) {
1890Sstevel@tonic-gate 	    cis_return_name(co, (cistpl_get_tuple_name_t *)arg);
1900Sstevel@tonic-gate 	    return (CISTPLF_NOERROR);
1910Sstevel@tonic-gate 	}
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	tp->flags |= CISTPLF_UNKNOWN;
1940Sstevel@tonic-gate 	return (CISTPLF_UNKNOWN);
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate /*
1980Sstevel@tonic-gate  * cis_no_tuple_handler - this generic tuple handler is used if no special
1990Sstevel@tonic-gate  *				tuple processing is required for the passed
2000Sstevel@tonic-gate  *				tuple
2010Sstevel@tonic-gate  *
2020Sstevel@tonic-gate  *	cistpl_callout_t *co - pointer to this tuple's entry in the
2030Sstevel@tonic-gate  *				tuple callout structure
2040Sstevel@tonic-gate  *	cistpl_t *tp - pointer to this tuple's entry in the local linked list
2050Sstevel@tonic-gate  *	int flags - action to perform
2060Sstevel@tonic-gate  *
2070Sstevel@tonic-gate  * This handler will set the CISTPLF_COPYOK flag if the tuple link is greater
2080Sstevel@tonic-gate  *	than zero, indicating that it's OK to copy the tuple data body. It
2090Sstevel@tonic-gate  *	will also set whatever flags are specified in the callout structure.
2100Sstevel@tonic-gate  *
2110Sstevel@tonic-gate  * We always set the CISTPLF_VALID when we're called with HANDTPL_COPY_DONE.
2120Sstevel@tonic-gate  *
2130Sstevel@tonic-gate  * We return CISTPLF_UNKNOWN if we're being called to parse the tuple.
2140Sstevel@tonic-gate  *
2150Sstevel@tonic-gate  * We return CISTPLF_NOERROR in every other case to indicate that this is a
2160Sstevel@tonic-gate  *	recognized tuple.
2170Sstevel@tonic-gate  */
2180Sstevel@tonic-gate /*ARGSUSED*/
2190Sstevel@tonic-gate uint32_t
cis_no_tuple_handler(cistpl_callout_t * co,cistpl_t * tp,uint32_t flags,void * arg)2200Sstevel@tonic-gate cis_no_tuple_handler(cistpl_callout_t *co, cistpl_t *tp,
2210Sstevel@tonic-gate 					uint32_t flags, void *arg)
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS) {
2240Sstevel@tonic-gate 		tp->flags |= co->flags;	/* XXX - is = the right thing here? */
2250Sstevel@tonic-gate 		if (tp->len > 0)
2260Sstevel@tonic-gate 			tp->flags |= CISTPLF_COPYOK;
2270Sstevel@tonic-gate 	}
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
2300Sstevel@tonic-gate 		tp->flags |= CISTPLF_VALID;
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE)
2330Sstevel@tonic-gate 	    return (CISTPLF_UNKNOWN);
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate /*
2390Sstevel@tonic-gate  * cis_unknown_tuple_handler - this generic tuple handler is used if we don't
2400Sstevel@tonic-gate  *				understand this tuple
2410Sstevel@tonic-gate  *
2420Sstevel@tonic-gate  *	cistpl_callout_t *co - pointer to this tuple's entry in the
2430Sstevel@tonic-gate  *				tuple callout structure
2440Sstevel@tonic-gate  *	cistpl_t *tp - pointer to this tuple's entry in the local linked list
2450Sstevel@tonic-gate  *	int flags - action to perform
2460Sstevel@tonic-gate  *
2470Sstevel@tonic-gate  * This handler will not set the CISTPLF_COPYOK flag since we don't know the
2480Sstevel@tonic-gate  *	contents of a vendor-specific tuple.
2490Sstevel@tonic-gate  *
2500Sstevel@tonic-gate  * We always set the CISTPLF_VALID when we're called with HANDTPL_COPY_DONE
2510Sstevel@tonic-gate  *	to specify that we understand this tuple's code, but not it's data
2520Sstevel@tonic-gate  *	body.
2530Sstevel@tonic-gate  *
2540Sstevel@tonic-gate  * We return CISTPLF_UNKNOWN if we're being called to parse the tuple or to
2550Sstevel@tonic-gate  *	perform any other operation.
2560Sstevel@tonic-gate  */
2570Sstevel@tonic-gate /*ARGSUSED*/
2580Sstevel@tonic-gate uint32_t
cis_unknown_tuple_handler(cistpl_callout_t * co,cistpl_t * tp,uint32_t flags,void * arg)2590Sstevel@tonic-gate cis_unknown_tuple_handler(cistpl_callout_t *co, cistpl_t *tp,
2600Sstevel@tonic-gate 					uint32_t flags, void *arg)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS) {
2630Sstevel@tonic-gate 		tp->flags |= co->flags;	/* XXX - is = the right thing here? */
2640Sstevel@tonic-gate 		return (CISTPLF_NOERROR);
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE) {
2680Sstevel@tonic-gate 		tp->flags |= CISTPLF_VALID;
2690Sstevel@tonic-gate 		return (CISTPLF_NOERROR);
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	return (CISTPLF_UNKNOWN);
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate /*
2760Sstevel@tonic-gate  * cistpl_vers_1_handler - handler for the CISTPL_VERS_1 tuple
2770Sstevel@tonic-gate  *
2780Sstevel@tonic-gate  *	void *arg - points to a cistpl_vers_1_t * where the
2790Sstevel@tonic-gate  *			information is stuffed into
2800Sstevel@tonic-gate  */
2810Sstevel@tonic-gate uint32_t
cistpl_vers_1_handler(cistpl_callout_t * co,cistpl_t * tp,uint32_t flags,void * arg)2820Sstevel@tonic-gate cistpl_vers_1_handler(cistpl_callout_t *co, cistpl_t *tp,
2830Sstevel@tonic-gate 					uint32_t flags, void *arg)
2840Sstevel@tonic-gate {
2850Sstevel@tonic-gate 	/*
2860Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
2870Sstevel@tonic-gate 	 *	generic handler for this
2880Sstevel@tonic-gate 	 */
2890Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
2900Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	/*
2930Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
2940Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
2950Sstevel@tonic-gate 	 */
2960Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
2970Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
3000Sstevel@tonic-gate 		cistpl_vers_1_t *cs = (cistpl_vers_1_t *)arg;
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 		RESET_TP(tp);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 		cs->major = GET_BYTE(tp);
3060Sstevel@tonic-gate 		cs->minor = GET_BYTE(tp);
3070Sstevel@tonic-gate 		for (cs->ns = 0; GET_LEN(tp) > 0 &&
3080Sstevel@tonic-gate 				/* CSTYLED */
3090Sstevel@tonic-gate 				cs->ns < CISTPL_VERS_1_MAX_PROD_STRINGS; ) {
3100Sstevel@tonic-gate 			(void) strcpy(cs->pi[cs->ns++], cis_getstr(tp));
3110Sstevel@tonic-gate 		} /* for */
3120Sstevel@tonic-gate 	} /* HANDTPL_PARSE_LTUPLE */
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate /*
3180Sstevel@tonic-gate  * cistpl_config_handler - handler for the CISTPL_CONFIG tuple
3190Sstevel@tonic-gate  *
3200Sstevel@tonic-gate  *	void *arg - points to a XXX where the information is stuffed into
3210Sstevel@tonic-gate  *
3220Sstevel@tonic-gate  * For the first ten config registers we set the present flags in the
3230Sstevel@tonic-gate  *	cistpl_config_t if the register exists.  The flags that we use
3240Sstevel@tonic-gate  *	for this are the same as the flags reguired for the Card Services
3250Sstevel@tonic-gate  *	RequestConfiguration function and they can be used by clients
3260Sstevel@tonic-gate  *	directly without requiring any remapping of values.
3270Sstevel@tonic-gate  *
3280Sstevel@tonic-gate  * XXX we don't handle TPCC_SBTPL subtuples yet
3290Sstevel@tonic-gate  */
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate uint32_t	config_regs_present_map[] = {
3320Sstevel@tonic-gate 	CONFIG_OPTION_REG_PRESENT,	/* COR present */
3330Sstevel@tonic-gate 	CONFIG_STATUS_REG_PRESENT,	/* STAT reg present */
3340Sstevel@tonic-gate 	CONFIG_PINREPL_REG_PRESENT,	/* PRR present */
3350Sstevel@tonic-gate 	CONFIG_COPY_REG_PRESENT,	/* COPY reg present */
3360Sstevel@tonic-gate 	CONFIG_EXSTAT_REG_PRESENT,	/* EXSTAT reg present */
3370Sstevel@tonic-gate 	CONFIG_IOBASE0_REG_PRESENT,	/* IOBASE0 reg present */
3380Sstevel@tonic-gate 	CONFIG_IOBASE1_REG_PRESENT,	/* IOBASE1 reg present */
3390Sstevel@tonic-gate 	CONFIG_IOBASE2_REG_PRESENT,	/* IOBASE2 reg present */
3400Sstevel@tonic-gate 	CONFIG_IOBASE3_REG_PRESENT,	/* IOBASE3 reg present */
3410Sstevel@tonic-gate 	CONFIG_IOLIMIT_REG_PRESENT,	/* IOLIMIT reg present */
3420Sstevel@tonic-gate };
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate uint32_t
cistpl_config_handler(cistpl_callout_t * co,cistpl_t * tp,uint32_t flags,void * arg)3450Sstevel@tonic-gate cistpl_config_handler(cistpl_callout_t *co, cistpl_t *tp,
3460Sstevel@tonic-gate 					uint32_t flags, void *arg)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 	cisdata_t tpcc_sz;
3490Sstevel@tonic-gate 	int i, n, nrb, na, hr = 0;
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	/*
3520Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
3530Sstevel@tonic-gate 	 *	generic handler for this
3540Sstevel@tonic-gate 	 */
3550Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
3560Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	/*
3590Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
3600Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
3610Sstevel@tonic-gate 	 */
3620Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
3630Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
3660Sstevel@tonic-gate 		cistpl_config_t *cr = (cistpl_config_t *)arg;
3670Sstevel@tonic-gate 		int crn = 0;
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 		RESET_TP(tp);
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 		tpcc_sz = GET_BYTE(tp);		/* config regs size fields */
3720Sstevel@tonic-gate 		cr->last = GET_BYTE(tp);	/* last config index */
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 		na = (tpcc_sz&3)+1;		/* config regs address bytes */
3750Sstevel@tonic-gate 		nrb = ((tpcc_sz>>2)&0x0f)+1;	/* number of bytes in config */
3760Sstevel@tonic-gate 						/*	regs presence mask */
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 		/*
3790Sstevel@tonic-gate 		 * Construct the base offset address for the config registers.
3800Sstevel@tonic-gate 		 *	We jump through these hoops because the base address
3810Sstevel@tonic-gate 		 *	can be between one and four bytes in length.
3820Sstevel@tonic-gate 		 */
3830Sstevel@tonic-gate 		cr->base = 0;
3840Sstevel@tonic-gate 		n = na;
3850Sstevel@tonic-gate 		while (n--)
3860Sstevel@tonic-gate 			cr->base |= ((GET_BYTE(tp) & 0x0ff) <<
3870Sstevel@tonic-gate 							(8 * (na - (n+1))));
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 		/*
3900Sstevel@tonic-gate 		 * Go through the config register presense mask bit by bit and
3910Sstevel@tonic-gate 		 *	figure out which config registers are present and which
3920Sstevel@tonic-gate 		 *	aren't.
3930Sstevel@tonic-gate 		 * For the first ten config registers, set the appropriate
3940Sstevel@tonic-gate 		 *	bits in the cr->present member so that the caller
3950Sstevel@tonic-gate 		 *	doesn't have to do this.
3960Sstevel@tonic-gate 		 */
3970Sstevel@tonic-gate 		cr->nr = 0;
3980Sstevel@tonic-gate 		cr->present = 0;
3990Sstevel@tonic-gate 		n = nrb;
4000Sstevel@tonic-gate 		while (n--) {
4010Sstevel@tonic-gate 			for (i = 0; i < 8; i++, crn++) {
4020Sstevel@tonic-gate 				if (LOOK_BYTE(tp) & (1<<i)) {
4030Sstevel@tonic-gate 				    if (crn < (sizeof (config_regs_present_map)/
4040Sstevel@tonic-gate 							sizeof (uint32_t)))
4050Sstevel@tonic-gate 					cr->present |=
4060Sstevel@tonic-gate 						config_regs_present_map[crn];
4070Sstevel@tonic-gate 				    cr->nr++;
4080Sstevel@tonic-gate 				    cr->hr = hr;
4090Sstevel@tonic-gate 				    cr->regs[hr] = MAKE_CONFIG_REG_ADDR(
4100Sstevel@tonic-gate 								cr->base, hr);
4110Sstevel@tonic-gate 				} /* LOOK_BYTE */
4120Sstevel@tonic-gate 				hr++;
4130Sstevel@tonic-gate 			} /* for */
4140Sstevel@tonic-gate 			(void) GET_BYTE(tp);
4150Sstevel@tonic-gate 		} /* while */
4160Sstevel@tonic-gate 	}
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate /*
4220Sstevel@tonic-gate  * cistpl_device_handler - handler for the CISTPL_DEVICE, CISTPL_DEVICE_A,
4230Sstevel@tonic-gate  *				CISTPL_DEVICE_OC and CISTPL_DEVICE_OA tuples
4240Sstevel@tonic-gate  *
4250Sstevel@tonic-gate  *	void *arg - points to a cistpl_device_t * where the
4260Sstevel@tonic-gate  *			information is stuffed into
4270Sstevel@tonic-gate  *
4280Sstevel@tonic-gate  * XXX - we only handle CISTPL_DEVICE_MAX_DEVICES device descriptions
4290Sstevel@tonic-gate  *		described in the tuple
4300Sstevel@tonic-gate  */
4310Sstevel@tonic-gate uint32_t
cistpl_device_handler(cistpl_callout_t * co,cistpl_t * tp,uint32_t flags,void * arg)4320Sstevel@tonic-gate cistpl_device_handler(cistpl_callout_t *co, cistpl_t *tp,
4330Sstevel@tonic-gate 					uint32_t flags, void *arg)
4340Sstevel@tonic-gate {
4350Sstevel@tonic-gate 	cisdata_t dev_id;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	/*
4380Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
4390Sstevel@tonic-gate 	 *	generic handler for this
4400Sstevel@tonic-gate 	 */
4410Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
4420Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	/*
4450Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
4460Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
4470Sstevel@tonic-gate 	 */
4480Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
4490Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
4520Sstevel@tonic-gate 		convert_speed_t convert_speed;
4530Sstevel@tonic-gate 		cistpl_device_t *dt = (cistpl_device_t *)arg;
4540Sstevel@tonic-gate 		cistpl_device_node_t *cdn;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 		/*
4570Sstevel@tonic-gate 		 * XXX - fix this to look for more than one device definition
4580Sstevel@tonic-gate 		 * XXX - fix this to handle the OC fields for
4590Sstevel@tonic-gate 		 *	CISTPL_DEVICE_OC and CISTPL_DEVICE_OA
4600Sstevel@tonic-gate 		 */
4610Sstevel@tonic-gate 		dt->num_devices = 1;
4620Sstevel@tonic-gate 		cdn = &dt->devnode[0];
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 		cdn->flags = 0;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		RESET_TP(tp);
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 		dev_id = GET_BYTE(tp);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 		/*
4710Sstevel@tonic-gate 		 * Get the device speed code.  If it's 7, then there is an
4720Sstevel@tonic-gate 		 *	extended speed code table in use, so parse that.
4730Sstevel@tonic-gate 		 *	If it's anything else, get the speed information
4740Sstevel@tonic-gate 		 *	directly from the device speed code.
4750Sstevel@tonic-gate 		 */
4760Sstevel@tonic-gate 		if ((dev_id & 7) == 7) {
4770Sstevel@tonic-gate 		    cdn->nS_speed = cistpl_devspeed(tp, 0, CISTPL_DEVSPEED_EXT);
4780Sstevel@tonic-gate 		} else {
4790Sstevel@tonic-gate 		    cdn->nS_speed = cistpl_devspeed(NULL, dev_id,
4800Sstevel@tonic-gate 							CISTPL_DEVSPEED_TABLE);
4810Sstevel@tonic-gate 		}
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 		/*
4840Sstevel@tonic-gate 		 * Convert the speed in nS to a device speed code.
4850Sstevel@tonic-gate 		 * XXX -  should check return code from cis_convert_devspeed()
4860Sstevel@tonic-gate 		 */
4870Sstevel@tonic-gate 		convert_speed.Attributes = CONVERT_NS_TO_DEVSPEED;
4880Sstevel@tonic-gate 		convert_speed.nS = cdn->nS_speed;
4890Sstevel@tonic-gate 		(void) cis_convert_devspeed(&convert_speed);
4900Sstevel@tonic-gate 		cdn->speed = convert_speed.devspeed;
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 		if (dev_id & 8)
4930Sstevel@tonic-gate 			cdn->flags |= CISTPL_DEVICE_WPS;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 		/*
4960Sstevel@tonic-gate 		 * Set the device type.  Note that we take the raw value
4970Sstevel@tonic-gate 		 *	from the tuple and pass it back to the caller.
4980Sstevel@tonic-gate 		 *	If the device type codes in the standard change,
4990Sstevel@tonic-gate 		 *	we will have to change our flags as well.
5000Sstevel@tonic-gate 		 */
5010Sstevel@tonic-gate 		cdn->type = (dev_id>>4) & 0x0f;
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 		/*
5040Sstevel@tonic-gate 		 * XXX - what about the device_size byte?  Is the spec wrong?
5050Sstevel@tonic-gate 		 */
5060Sstevel@tonic-gate 		cdn->size = GET_BYTE(tp);
5070Sstevel@tonic-gate 		/* check for end of list */
5080Sstevel@tonic-gate 		if (cdn->size != 0x0ff) {
5090Sstevel@tonic-gate 		    convert_size_t convert_size;
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 		    convert_size.devsize = cdn->size;
5120Sstevel@tonic-gate 		    convert_size.Attributes = CONVERT_DEVSIZE_TO_BYTES;
5130Sstevel@tonic-gate 		    (void) cis_convert_devsize(&convert_size);
5140Sstevel@tonic-gate 		    cdn->size_in_bytes = convert_size.bytes;
5150Sstevel@tonic-gate 		}
5160Sstevel@tonic-gate 	}
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate /*
5220Sstevel@tonic-gate  * cistpl_cftable_handler - handler for the CISTPL_CFTABLE_ENTRY tuple
5230Sstevel@tonic-gate  *
5240Sstevel@tonic-gate  *	void *arg - points to a XXX where the information is stuffed into
5250Sstevel@tonic-gate  *
5260Sstevel@tonic-gate  *    Return:	CISTPLF_NOERROR - if no error parsing tuple
5270Sstevel@tonic-gate  *		HANDTPL_ERROR - if error parsing tuple
5280Sstevel@tonic-gate  */
5290Sstevel@tonic-gate extern uint32_t cistpl_cftable_io_size_table[];
5300Sstevel@tonic-gate extern uint32_t cistpl_cftable_shift_table[];
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate uint32_t
cistpl_cftable_handler(cistpl_callout_t * co,cistpl_t * tp,uint32_t flags,void * arg)5330Sstevel@tonic-gate cistpl_cftable_handler(cistpl_callout_t *co, cistpl_t *tp,
5340Sstevel@tonic-gate 					uint32_t flags, void *arg)
5350Sstevel@tonic-gate {
5360Sstevel@tonic-gate 	cisdata_t tpce_indx, tpce_fs, tpce_td, sf, tpce_io, nr;
5370Sstevel@tonic-gate 	cisdata_t ior_desc, tpce_ir, tpce_msd;
5380Sstevel@tonic-gate 	int i, j;
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	/*
5410Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
5420Sstevel@tonic-gate 	 *	generic handler for this
5430Sstevel@tonic-gate 	 */
5440Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
5450Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	/*
5480Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
5490Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
5500Sstevel@tonic-gate 	 */
5510Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
5520Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
5550Sstevel@tonic-gate 		cistpl_cftable_entry_t *ce = (cistpl_cftable_entry_t *)arg;
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 		RESET_TP(tp);
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 		/*
5600Sstevel@tonic-gate 		 * Check to see if we have an interface description byte.  If
5610Sstevel@tonic-gate 		 *	we do, grab it and give it directly to the caller, and
5620Sstevel@tonic-gate 		 *	set a flag so the caller knows that it's there.
5630Sstevel@tonic-gate 		 * We also setup the appropriate values in the ce->pin member
5640Sstevel@tonic-gate 		 *	so that clients can feed this value directly to the
5650Sstevel@tonic-gate 		 *	Card Services RequestConfiguration call.
5660Sstevel@tonic-gate 		 */
5670Sstevel@tonic-gate 		if ((tpce_indx = GET_BYTE(tp)) & CISTPL_CFTABLE_TPCE_IFM) {
5680Sstevel@tonic-gate 			ce->ifc = GET_BYTE(tp);
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 			ce->pin = 0;
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 			if (ce->ifc & CISTPL_CFTABLE_TPCE_IF_BVD)
5730Sstevel@tonic-gate 			    ce->pin |= (PRR_BVD1_STATUS | PRR_BVD2_STATUS |
5740Sstevel@tonic-gate 					PRR_BVD1_EVENT | PRR_BVD2_EVENT);
5750Sstevel@tonic-gate 			if (ce->ifc & CISTPL_CFTABLE_TPCE_IF_WP)
5760Sstevel@tonic-gate 			    ce->pin |= (PRR_WP_STATUS | PRR_WP_EVENT);
5770Sstevel@tonic-gate 			if (ce->ifc & CISTPL_CFTABLE_TPCE_IF_RDY)
5780Sstevel@tonic-gate 			    ce->pin |= (PRR_READY_STATUS | PRR_READY_EVENT);
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 			ce->flags |= CISTPL_CFTABLE_TPCE_IF;
5810Sstevel@tonic-gate 		}
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 		/*
5840Sstevel@tonic-gate 		 * Return the configuration index to the caller, and set the
5850Sstevel@tonic-gate 		 *	default configuration flag if this is a default
5860Sstevel@tonic-gate 		 *	configuration.
5870Sstevel@tonic-gate 		 */
5880Sstevel@tonic-gate 		ce->index = tpce_indx & CISTPL_CFTABLE_TPCE_CFGENTRYM;
5890Sstevel@tonic-gate 		if (tpce_indx & CISTPL_CFTABLE_TPCE_DEFAULTM)
5900Sstevel@tonic-gate 			ce->flags |= CISTPL_CFTABLE_TPCE_DEFAULT;
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 		/*
5930Sstevel@tonic-gate 		 * Feature selection flags.
5940Sstevel@tonic-gate 		 */
5950Sstevel@tonic-gate 		tpce_fs = GET_BYTE(tp);
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 		/*
5980Sstevel@tonic-gate 		 * See what types of power information are available,
5990Sstevel@tonic-gate 		 *	and if there is any, set the global power
6000Sstevel@tonic-gate 		 *	information flag as well as a flag for each
6010Sstevel@tonic-gate 		 *	power description available.
6020Sstevel@tonic-gate 		 */
6030Sstevel@tonic-gate 		if (tpce_fs & CISTPL_CFTABLE_TPCE_FS_PWRM) {
6040Sstevel@tonic-gate 		    cistpl_cftable_entry_pd_t *pd = &ce->pd;
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 		    ce->flags |= CISTPL_CFTABLE_TPCE_FS_PWR;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 		    switch (tpce_fs & CISTPL_CFTABLE_TPCE_FS_PWRM) {
6090Sstevel@tonic-gate 			case CISTPL_CFTABLE_TPCE_FS_PWR_VPP2M:
6100Sstevel@tonic-gate 				pd->flags |= CISTPL_CFTABLE_TPCE_FS_PWR_VPP2;
6110Sstevel@tonic-gate 				/* FALLTHROUGH */
6120Sstevel@tonic-gate 			case CISTPL_CFTABLE_TPCE_FS_PWR_VPP1M:
6130Sstevel@tonic-gate 				pd->flags |= CISTPL_CFTABLE_TPCE_FS_PWR_VPP1;
6140Sstevel@tonic-gate 				/* FALLTHROUGH */
6150Sstevel@tonic-gate 			case CISTPL_CFTABLE_TPCE_FS_PWR_VCCM:
6160Sstevel@tonic-gate 				pd->flags |= CISTPL_CFTABLE_TPCE_FS_PWR_VCC;
6170Sstevel@tonic-gate 		    } /* switch */
6180Sstevel@tonic-gate 		} /* if (CISTPL_CFTABLE_TPCE_FS_PWRM) */
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 		/*
6210Sstevel@tonic-gate 		 * Set up the global memory information flag.
6220Sstevel@tonic-gate 		 */
6230Sstevel@tonic-gate 		if (tpce_fs & CISTPL_CFTABLE_TPCE_FS_MEMM)
6240Sstevel@tonic-gate 			ce->flags |= CISTPL_CFTABLE_TPCE_FS_MEM;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 		/*
6270Sstevel@tonic-gate 		 * Parse the various power description structures.
6280Sstevel@tonic-gate 		 */
6290Sstevel@tonic-gate 		if (ce->flags & CISTPL_CFTABLE_TPCE_FS_PWR) {
6300Sstevel@tonic-gate 			cistpl_cftable_entry_pd_t *pd = &ce->pd;
6310Sstevel@tonic-gate 			cistpl_cftable_entry_pwr_t *pwr;
6320Sstevel@tonic-gate 			/*
6330Sstevel@tonic-gate 			 * Collect any Vcc information.
6340Sstevel@tonic-gate 			 */
6350Sstevel@tonic-gate 			if (pd->flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) {
6360Sstevel@tonic-gate 				pwr = &pd->pd_vcc;
6370Sstevel@tonic-gate 				cistpl_pd_parse(tp, pwr);
6380Sstevel@tonic-gate 			}
6390Sstevel@tonic-gate 			/*
6400Sstevel@tonic-gate 			 * Collect any Vpp1 information.
6410Sstevel@tonic-gate 			 */
6420Sstevel@tonic-gate 			if (pd->flags & CISTPL_CFTABLE_TPCE_FS_PWR_VPP1) {
6430Sstevel@tonic-gate 				pwr = &pd->pd_vpp1;
6440Sstevel@tonic-gate 				cistpl_pd_parse(tp, pwr);
6450Sstevel@tonic-gate 			}
6460Sstevel@tonic-gate 			/*
6470Sstevel@tonic-gate 			 * Collect any Vpp2 information.
6480Sstevel@tonic-gate 			 */
6490Sstevel@tonic-gate 			if (pd->flags & CISTPL_CFTABLE_TPCE_FS_PWR_VPP2) {
6500Sstevel@tonic-gate 				pwr = &pd->pd_vpp2;
6510Sstevel@tonic-gate 				cistpl_pd_parse(tp, pwr);
6520Sstevel@tonic-gate 			}
6530Sstevel@tonic-gate 		} /* if (CISTPL_CFTABLE_TPCE_FS_PWR) */
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 		/*
6560Sstevel@tonic-gate 		 * Check to see if there's any timing information, and if
6570Sstevel@tonic-gate 		 *	so, parse the tuple data and store it in the
6580Sstevel@tonic-gate 		 *	caller's structure.  Set a flag in the global
6590Sstevel@tonic-gate 		 *	flag field indicating that there is timing information.
6600Sstevel@tonic-gate 		 */
6610Sstevel@tonic-gate 		if (tpce_fs & CISTPL_CFTABLE_TPCE_FS_TDM) {
6620Sstevel@tonic-gate 			convert_speed_t convert_speed;
6630Sstevel@tonic-gate 			cistpl_cftable_entry_speed_t *sp = &ce->speed;
6640Sstevel@tonic-gate 			ce->flags |= CISTPL_CFTABLE_TPCE_FS_TD;
6650Sstevel@tonic-gate 			tpce_td = GET_BYTE(tp);
6660Sstevel@tonic-gate 			/*
6670Sstevel@tonic-gate 			 * Parse TPCE_TD to get the various timing
6680Sstevel@tonic-gate 			 *	scale factors. Each scale factor has
6690Sstevel@tonic-gate 			 *	a value that indicates that the particular
6700Sstevel@tonic-gate 			 *	timing parameter doesn't exist.
6710Sstevel@tonic-gate 			 */
6720Sstevel@tonic-gate 			if ((sf = (tpce_td &
6730Sstevel@tonic-gate 					CISTPL_CFTABLE_TPCE_FS_TD_WAITM)) !=
6740Sstevel@tonic-gate 			    CISTPL_CFTABLE_TPCE_FS_TD_WAITM) {
6750Sstevel@tonic-gate 				sp->nS_wait = cistpl_devspeed(tp,
6760Sstevel@tonic-gate 						GET_TPCE_FS_TD_WAITS(sf),
6770Sstevel@tonic-gate 						CISTPL_DEVSPEED_EXT);
6780Sstevel@tonic-gate 				convert_speed.Attributes =
6790Sstevel@tonic-gate 							CONVERT_NS_TO_DEVSPEED;
6800Sstevel@tonic-gate 				convert_speed.nS = sp->nS_wait;
6810Sstevel@tonic-gate 				(void) cis_convert_devspeed(&convert_speed);
6820Sstevel@tonic-gate 				sp->wait = convert_speed.devspeed;
6830Sstevel@tonic-gate 				sp->flags |= CISTPL_CFTABLE_TPCE_FS_TD_WAIT;
6840Sstevel@tonic-gate 			}
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 			if ((sf = (tpce_td & CISTPL_CFTABLE_TPCE_FS_TD_RDYM)) !=
6870Sstevel@tonic-gate 			    CISTPL_CFTABLE_TPCE_FS_TD_RDYM) {
6880Sstevel@tonic-gate 				sp->nS_rdybsy = cistpl_devspeed(tp,
6890Sstevel@tonic-gate 						GET_TPCE_FS_TD_RDYS(sf),
6900Sstevel@tonic-gate 						CISTPL_DEVSPEED_EXT);
6910Sstevel@tonic-gate 				convert_speed.Attributes =
6920Sstevel@tonic-gate 							CONVERT_NS_TO_DEVSPEED;
6930Sstevel@tonic-gate 				convert_speed.nS = sp->nS_rdybsy;
6940Sstevel@tonic-gate 				(void) cis_convert_devspeed(&convert_speed);
6950Sstevel@tonic-gate 				sp->rdybsy = convert_speed.devspeed;
6960Sstevel@tonic-gate 				sp->flags |= CISTPL_CFTABLE_TPCE_FS_TD_RDY;
6970Sstevel@tonic-gate 			}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 			if ((sf = (tpce_td &
7000Sstevel@tonic-gate 					CISTPL_CFTABLE_TPCE_FS_TD_RSVDM)) !=
7010Sstevel@tonic-gate 			    CISTPL_CFTABLE_TPCE_FS_TD_RSVDM) {
7020Sstevel@tonic-gate 				sp->nS_rsvd = cistpl_devspeed(tp,
7030Sstevel@tonic-gate 						GET_TPCE_FS_TD_RSVDS(sf),
7040Sstevel@tonic-gate 						CISTPL_DEVSPEED_EXT);
7050Sstevel@tonic-gate 				convert_speed.Attributes =
7060Sstevel@tonic-gate 							CONVERT_NS_TO_DEVSPEED;
7070Sstevel@tonic-gate 				convert_speed.nS = sp->nS_rsvd;
7080Sstevel@tonic-gate 				(void) cis_convert_devspeed(&convert_speed);
7090Sstevel@tonic-gate 				sp->rsvd = convert_speed.devspeed;
7100Sstevel@tonic-gate 				sp->flags |= CISTPL_CFTABLE_TPCE_FS_TD_RSVD;
7110Sstevel@tonic-gate 			}
7120Sstevel@tonic-gate 		} /* if (CISTPL_CFTABLE_TPCE_FS_TDM) */
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 		/*
7160Sstevel@tonic-gate 		 * Parse any I/O address information.  If there is I/O
7170Sstevel@tonic-gate 		 *	inforamtion, set a flag in the global flag field
7180Sstevel@tonic-gate 		 *	to let the caller know.
7190Sstevel@tonic-gate 		 */
7200Sstevel@tonic-gate 		if (tpce_fs & CISTPL_CFTABLE_TPCE_FS_IOM) {
7210Sstevel@tonic-gate 			cistpl_cftable_entry_io_t *io = &ce->io;
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 			ce->flags |= CISTPL_CFTABLE_TPCE_FS_IO;
7240Sstevel@tonic-gate 			tpce_io = GET_BYTE(tp);
7250Sstevel@tonic-gate 			/*
7260Sstevel@tonic-gate 			 * Pass any I/O flags that are in the tuple directly
7270Sstevel@tonic-gate 			 *	to the caller.
7280Sstevel@tonic-gate 			 */
7290Sstevel@tonic-gate 			io->flags = tpce_io;
7300Sstevel@tonic-gate 			io->addr_lines = tpce_io &
7310Sstevel@tonic-gate 						CISTPL_CFTABLE_TPCE_FS_IO_ALM;
7320Sstevel@tonic-gate 			/*
7330Sstevel@tonic-gate 			 * If there are any ranges, extract the number of
7340Sstevel@tonic-gate 			 *	ranges and the range descriptions.
7350Sstevel@tonic-gate 			 */
7360Sstevel@tonic-gate 			if (tpce_io & CISTPL_CFTABLE_TPCE_FS_IO_RANGEM) {
7370Sstevel@tonic-gate 				cistpl_cftable_entry_io_range_t *ior;
7380Sstevel@tonic-gate 				ior_desc = GET_BYTE(tp);
7390Sstevel@tonic-gate 				/*
7400Sstevel@tonic-gate 				 * Number of I/O ranges is the value specified
7410Sstevel@tonic-gate 				 *	in the tuple plus one, so there's
7420Sstevel@tonic-gate 				 *	always at least one I/O range if the
7430Sstevel@tonic-gate 				 *	CISTPL_CFTABLE_TPCE_FS_IO_RANGEM bit
7440Sstevel@tonic-gate 				 *	in the I/O flags register is set.
7450Sstevel@tonic-gate 				 */
7460Sstevel@tonic-gate 				nr = (ior_desc & 0x0f) + 1;
7470Sstevel@tonic-gate 				io->ranges = nr;
7480Sstevel@tonic-gate 				/*
7490Sstevel@tonic-gate 				 * Cycle through each I/O range.
7500Sstevel@tonic-gate 				 */
7510Sstevel@tonic-gate 				for (i = 0; i < (int)nr; i++) {
7520Sstevel@tonic-gate 					ior = &io->range[i];
7530Sstevel@tonic-gate 					ior->addr = 0;
7540Sstevel@tonic-gate 					ior->length = 0;
7550Sstevel@tonic-gate 					/*
7560Sstevel@tonic-gate 					 * Gather the address information.
7570Sstevel@tonic-gate 					 *	It's OK if there's no address
7580Sstevel@tonic-gate 					 *	information in which case this
7590Sstevel@tonic-gate 					 *	loop will never execute.
7600Sstevel@tonic-gate 					 */
7610Sstevel@tonic-gate 					for (j = 0; j <
7620Sstevel@tonic-gate 						cistpl_cftable_io_size_table[
7630Sstevel@tonic-gate 							(ior_desc>>4)&3];
7640Sstevel@tonic-gate 									j++)
7650Sstevel@tonic-gate 						ior->addr |= (GET_BYTE(tp) <<
7660Sstevel@tonic-gate 						cistpl_cftable_shift_table[j]);
7670Sstevel@tonic-gate 					/*
7680Sstevel@tonic-gate 					 * Gather the length information.
7690Sstevel@tonic-gate 					 *	It's OK if there's no length
7700Sstevel@tonic-gate 					 *	information in which case this
7710Sstevel@tonic-gate 					 *	loop will never execute.
7720Sstevel@tonic-gate 					 */
7730Sstevel@tonic-gate 					for (j = 0; j <
7740Sstevel@tonic-gate 						cistpl_cftable_io_size_table[
7750Sstevel@tonic-gate 							(ior_desc>>6)&3];
7760Sstevel@tonic-gate 									j++)
7770Sstevel@tonic-gate 						ior->length |= (GET_BYTE(tp) <<
7780Sstevel@tonic-gate 						cistpl_cftable_shift_table[j]);
7790Sstevel@tonic-gate 				} /* for (nr) */
7800Sstevel@tonic-gate 			} /* if (CISTPL_CFTABLE_TPCE_FS_IO_RANGEM) */
7810Sstevel@tonic-gate 		} /* if (CISTPL_CFTABLE_TPCE_FS_IOM) */
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 		/*
7840Sstevel@tonic-gate 		 * Parse any IRQ information.  If there is IRQ inforamtion,
7850Sstevel@tonic-gate 		 *	set a flag in the global flag field to let the
7860Sstevel@tonic-gate 		 *	caller know.
7870Sstevel@tonic-gate 		 */
7880Sstevel@tonic-gate 		if (tpce_fs & CISTPL_CFTABLE_TPCE_FS_IRQM) {
7890Sstevel@tonic-gate 			cistpl_cftable_entry_irq_t *irq = &ce->irq;
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 			ce->flags |= CISTPL_CFTABLE_TPCE_FS_IRQ;
7920Sstevel@tonic-gate 			tpce_ir = GET_BYTE(tp);
7930Sstevel@tonic-gate 			/*
7940Sstevel@tonic-gate 			 * Pass any IRQ flags that are in the tuple directly
7950Sstevel@tonic-gate 			 *	to the caller.
7960Sstevel@tonic-gate 			 */
7970Sstevel@tonic-gate 			irq->flags = tpce_ir;
7980Sstevel@tonic-gate 			/*
7990Sstevel@tonic-gate 			 * Check for and parse the extended IRQ bitmask
8000Sstevel@tonic-gate 			 *	if it exists.
8010Sstevel@tonic-gate 			 */
8020Sstevel@tonic-gate 			if (tpce_ir & CISTPL_CFTABLE_TPCE_FS_IRQ_MASKM) {
8030Sstevel@tonic-gate 				irq->irqs = GET_BYTE(tp) & 0x0ff;
8040Sstevel@tonic-gate 				irq->irqs |= (GET_BYTE(tp) << 8)&0x0ff00;
8050Sstevel@tonic-gate 			} else {
8060Sstevel@tonic-gate 				irq->irqs = (1<< (tpce_ir&0x0f));
8070Sstevel@tonic-gate 			}
8080Sstevel@tonic-gate 		} /* if (CISTPL_CFTABLE_TPCE_FS_IRQM) */
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 		/*
8110Sstevel@tonic-gate 		 * Parse any memory information.
8120Sstevel@tonic-gate 		 *
8130Sstevel@tonic-gate 		 * XXX - should be a cleaner way to parse this information.
8140Sstevel@tonic-gate 		 */
8150Sstevel@tonic-gate 		if (ce->flags & CISTPL_CFTABLE_TPCE_FS_MEM) {
8160Sstevel@tonic-gate 			cistpl_cftable_entry_mem_t *mem = &ce->mem;
8170Sstevel@tonic-gate 			cistpl_cftable_entry_mem_window_t *win;
8180Sstevel@tonic-gate 			/*
8190Sstevel@tonic-gate 			 * Switch on the type of memory description
8200Sstevel@tonic-gate 			 *	information that is available.
8210Sstevel@tonic-gate 			 */
8220Sstevel@tonic-gate 			switch (tpce_fs & CISTPL_CFTABLE_TPCE_FS_MEMM) {
8230Sstevel@tonic-gate 				/*
8240Sstevel@tonic-gate 				 * variable length memory space description
8250Sstevel@tonic-gate 				 */
8260Sstevel@tonic-gate 			case CISTPL_CFTABLE_TPCE_FS_MEM3M:
8270Sstevel@tonic-gate 				mem->flags |= CISTPL_CFTABLE_TPCE_FS_MEM3;
8280Sstevel@tonic-gate 				/* memory space descriptor */
8290Sstevel@tonic-gate 				tpce_msd = GET_BYTE(tp);
8300Sstevel@tonic-gate 				mem->windows = ((tpce_msd &
8310Sstevel@tonic-gate 					(CISTPL_CFTABLE_ENTRY_MAX_MEM_WINDOWS -
8320Sstevel@tonic-gate 								1)) + 1);
8330Sstevel@tonic-gate 				/*
8340Sstevel@tonic-gate 				 * If there's host address information, let
8350Sstevel@tonic-gate 				 *	the caller know.
8360Sstevel@tonic-gate 				 */
8370Sstevel@tonic-gate 				if (tpce_msd & CISTPL_CFTABLE_TPCE_FS_MEM_HOSTM)
8380Sstevel@tonic-gate 					mem->flags |=
8390Sstevel@tonic-gate 						CISTPL_CFTABLE_TPCE_FS_MEM_HOST;
8400Sstevel@tonic-gate 				/*
8410Sstevel@tonic-gate 				 * Cycle through each window space description
8420Sstevel@tonic-gate 				 *	and collect all the interesting bits.
8430Sstevel@tonic-gate 				 */
8440Sstevel@tonic-gate 				for (i = 0; i < mem->windows; i++) {
8450Sstevel@tonic-gate 					win = &mem->window[i];
8460Sstevel@tonic-gate 					win->length = 0;
8470Sstevel@tonic-gate 					win->card_addr = 0;
8480Sstevel@tonic-gate 					win->host_addr = 0;
8490Sstevel@tonic-gate 					/*
8500Sstevel@tonic-gate 					 * Gather the length information.
8510Sstevel@tonic-gate 					 *	It's OK if there's no length
8520Sstevel@tonic-gate 					 *	information in which case this
8530Sstevel@tonic-gate 					 *	loop will never execute.
8540Sstevel@tonic-gate 					 */
8550Sstevel@tonic-gate 					for (j = 0; j <
8560Sstevel@tonic-gate 						(int)((tpce_msd>>3)&3); j++)
8570Sstevel@tonic-gate 						win->length |= (GET_BYTE(tp) <<
8580Sstevel@tonic-gate 						cistpl_cftable_shift_table[j]);
8590Sstevel@tonic-gate 					/*
8600Sstevel@tonic-gate 					 * Gather the card address information.
8610Sstevel@tonic-gate 					 *	It's OK if there's no card
8620Sstevel@tonic-gate 					 *	address information in which
8630Sstevel@tonic-gate 					 *	case this loop will never
8640Sstevel@tonic-gate 					 *	execute.
8650Sstevel@tonic-gate 					 */
8660Sstevel@tonic-gate 					for (j = 0; j <
8670Sstevel@tonic-gate 						(int)((tpce_msd>>5)&3); j++)
8680Sstevel@tonic-gate 						win->card_addr |=
8690Sstevel@tonic-gate 							(GET_BYTE(tp) <<
8700Sstevel@tonic-gate 						cistpl_cftable_shift_table[j]);
8710Sstevel@tonic-gate 					/*
8720Sstevel@tonic-gate 					 * If there's a host address
8730Sstevel@tonic-gate 					 *	description, grab that
8740Sstevel@tonic-gate 					 *	as well.
8750Sstevel@tonic-gate 					 */
8760Sstevel@tonic-gate 					if (mem->flags &
8770Sstevel@tonic-gate 					    CISTPL_CFTABLE_TPCE_FS_MEM_HOST) {
8780Sstevel@tonic-gate 						/*
8790Sstevel@tonic-gate 						 * Gather the host address
8800Sstevel@tonic-gate 						 *	information.  It's OK
8810Sstevel@tonic-gate 						 *	if there's no host
8820Sstevel@tonic-gate 						 *	address information in
8830Sstevel@tonic-gate 						 *	which case this loop
8840Sstevel@tonic-gate 						 *	will never execute.
8850Sstevel@tonic-gate 						 * Note that we use the card
8860Sstevel@tonic-gate 						 *	address size to
8870Sstevel@tonic-gate 						 *	determine how many
8880Sstevel@tonic-gate 						 *	bytes of host address
8890Sstevel@tonic-gate 						 *	are present.
8900Sstevel@tonic-gate 						 */
8910Sstevel@tonic-gate 						for (j = 0; j <
8920Sstevel@tonic-gate 							(int)((tpce_msd>>5)&3);
8930Sstevel@tonic-gate 									j++)
8940Sstevel@tonic-gate 							win->host_addr |=
8950Sstevel@tonic-gate 							(GET_BYTE(tp) <<
8960Sstevel@tonic-gate 						cistpl_cftable_shift_table[j]);
8970Sstevel@tonic-gate 					} else {
8980Sstevel@tonic-gate 						/*
8990Sstevel@tonic-gate 						 * No host address information,
9000Sstevel@tonic-gate 						 *	so the host address is
9010Sstevel@tonic-gate 						 *	equal to the card
9020Sstevel@tonic-gate 						 *	address.
9030Sstevel@tonic-gate 						 */
9040Sstevel@tonic-gate 						win->host_addr = win->card_addr;
9050Sstevel@tonic-gate 					}
9060Sstevel@tonic-gate 				} /* for (i<mem->windows) */
9070Sstevel@tonic-gate 				break;
9080Sstevel@tonic-gate 				/*
9090Sstevel@tonic-gate 				 * single length and card base address specified
9100Sstevel@tonic-gate 				 */
9110Sstevel@tonic-gate 			case CISTPL_CFTABLE_TPCE_FS_MEM2M:
9120Sstevel@tonic-gate 				mem->flags |= CISTPL_CFTABLE_TPCE_FS_MEM2;
9130Sstevel@tonic-gate 				win = &mem->window[0];
9140Sstevel@tonic-gate 				mem->windows = 1;
9150Sstevel@tonic-gate 				/*
9160Sstevel@tonic-gate 				 * Construct the size of the window.
9170Sstevel@tonic-gate 				 */
9180Sstevel@tonic-gate 				win->length = GET_BYTE(tp);
9190Sstevel@tonic-gate 				win->length |= (GET_BYTE(tp)<<8);
9200Sstevel@tonic-gate 				win->length *=
9210Sstevel@tonic-gate 					CISTPL_CFTABLE_TPCE_FS_MEM_PGSIZE;
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 				/*
9240Sstevel@tonic-gate 				 * Construct the card base address.
9250Sstevel@tonic-gate 				 */
9260Sstevel@tonic-gate 				win->card_addr = GET_BYTE(tp);
9270Sstevel@tonic-gate 				win->card_addr |= (GET_BYTE(tp)<<8);
9280Sstevel@tonic-gate 				win->card_addr *=
9290Sstevel@tonic-gate 					CISTPL_CFTABLE_TPCE_FS_MEM_PGSIZE;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 				/*
9320Sstevel@tonic-gate 				 * In this mode, both the host base address
9330Sstevel@tonic-gate 				 *	and the card base address are equal.
9340Sstevel@tonic-gate 				 */
9350Sstevel@tonic-gate 				win->host_addr = win->card_addr;
9360Sstevel@tonic-gate 				break;
9370Sstevel@tonic-gate 				/*
9380Sstevel@tonic-gate 				 * single length specified
9390Sstevel@tonic-gate 				 */
9400Sstevel@tonic-gate 			case CISTPL_CFTABLE_TPCE_FS_MEM1M:
9410Sstevel@tonic-gate 				mem->flags |= CISTPL_CFTABLE_TPCE_FS_MEM1;
9420Sstevel@tonic-gate 				win = &mem->window[0];
9430Sstevel@tonic-gate 				mem->windows = 1;
9440Sstevel@tonic-gate 				win->card_addr = 0;
9450Sstevel@tonic-gate 				win->host_addr = 0;
9460Sstevel@tonic-gate 				/*
9470Sstevel@tonic-gate 				 * Construct the size of the window.
9480Sstevel@tonic-gate 				 */
9490Sstevel@tonic-gate 				win->length = GET_BYTE(tp);
9500Sstevel@tonic-gate 				win->length |= (GET_BYTE(tp)<<8);
9510Sstevel@tonic-gate 				win->length *=
9520Sstevel@tonic-gate 					CISTPL_CFTABLE_TPCE_FS_MEM_PGSIZE;
9530Sstevel@tonic-gate 				break;
9540Sstevel@tonic-gate 			} /* switch (CISTPL_CFTABLE_TPCE_FS_MEMM) */
9550Sstevel@tonic-gate 		} /* if (CISTPL_CFTABLE_TPCE_FS_MEM) */
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 		/*
9580Sstevel@tonic-gate 		 * Check for and parse any miscellaneous information.
9590Sstevel@tonic-gate 		 *
9600Sstevel@tonic-gate 		 * We only understand how to parse the first
9610Sstevel@tonic-gate 		 *	CISTPL_CFTABLE_TPCE_FS_MISC_MAX extension
9620Sstevel@tonic-gate 		 *	bytes specified in the PC Card 95 standard;
9630Sstevel@tonic-gate 		 *	we throw away any other extension bytes that
9640Sstevel@tonic-gate 		 *	are past these bytes.
9650Sstevel@tonic-gate 		 * XXX Note that the assumption here is that the
9660Sstevel@tonic-gate 		 *	size of cistpl_cftable_entry_misc_t->flags
9670Sstevel@tonic-gate 		 *	is at least CISTPL_CFTABLE_TPCE_FS_MISC_MAX
9680Sstevel@tonic-gate 		 *	bytes in length.
9690Sstevel@tonic-gate 		 */
9700Sstevel@tonic-gate 		if (tpce_fs & CISTPL_CFTABLE_TPCE_FS_MISCM) {
9710Sstevel@tonic-gate 		    cistpl_cftable_entry_misc_t *misc = &ce->misc;
9720Sstevel@tonic-gate 		    int mb = CISTPL_CFTABLE_TPCE_FS_MISC_MAX;
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 		    ce->flags |= CISTPL_CFTABLE_TPCE_FS_MISC;
9750Sstevel@tonic-gate 		    misc->flags = 0;
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 		    do {
9780Sstevel@tonic-gate 			if (mb) {
9790Sstevel@tonic-gate 			    misc->flags = (misc->flags << 8) | LOOK_BYTE(tp);
9800Sstevel@tonic-gate 			    mb--;
9810Sstevel@tonic-gate 			}
9820Sstevel@tonic-gate 		    } while ((GET_BYTE(tp) & CISTPL_EXT_BIT) &&
9830Sstevel@tonic-gate 				(!(tp->flags & CISTPLF_MEM_ERR)));
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 			/*
9860Sstevel@tonic-gate 			 * Check to see if we tried to read past the
9870Sstevel@tonic-gate 			 *	end of the tuple data; if we have,
9880Sstevel@tonic-gate 			 *	there's no point in trying to parse
9890Sstevel@tonic-gate 			 *	any more of the tuple.
9900Sstevel@tonic-gate 			 */
9910Sstevel@tonic-gate 		    if (tp->flags & CISTPLF_MEM_ERR)
9920Sstevel@tonic-gate 			return (HANDTPL_ERROR);
9930Sstevel@tonic-gate 		} /* if (CISTPL_CFTABLE_TPCE_FS_MISCM) */
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 		/*
9960Sstevel@tonic-gate 		 * Check for and parse any additional subtuple
9970Sstevel@tonic-gate 		 *	information. We know that there is
9980Sstevel@tonic-gate 		 *	additional information if we haven't
9990Sstevel@tonic-gate 		 *	reached the end of the tuple data area
10000Sstevel@tonic-gate 		 *	and if the additional information is
10010Sstevel@tonic-gate 		 *	in standard tuple format.
10020Sstevel@tonic-gate 		 * If we don't recognize the additional info,
10030Sstevel@tonic-gate 		 *	then just silently ignore it, don't
10040Sstevel@tonic-gate 		 *	flag it as an error.
10050Sstevel@tonic-gate 		 */
10060Sstevel@tonic-gate #ifdef	PARSE_STCE_TUPLES
10070Sstevel@tonic-gate 		if (GET_LEN(tp) > 0) {
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 		ce->flags |= CISTPL_CFTABLE_TPCE_FS_STCE_EV
10100Sstevel@tonic-gate 		ce->flags |= CISTPL_CFTABLE_TPCE_FS_STCE_PD
10110Sstevel@tonic-gate #endif
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	} /* if (HANDTPL_PARSE_LTUPLE) */
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
10160Sstevel@tonic-gate }
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate /*
10190Sstevel@tonic-gate  * cistpl_pd_parse - read and parse a power description structure
10200Sstevel@tonic-gate  *
10210Sstevel@tonic-gate  *	cisdata_t **ddp - pointer to pointer tuple data area
10220Sstevel@tonic-gate  *	cistpl_cftable_entry_pwr_t *pd - pointer to local power description
10230Sstevel@tonic-gate  *					structure
10240Sstevel@tonic-gate  */
10250Sstevel@tonic-gate static void
10260Sstevel@tonic-gate cistpl_pd_parse(cistpl_t *tp, cistpl_cftable_entry_pwr_t *pd)
10270Sstevel@tonic-gate {
10280Sstevel@tonic-gate 	cisdata_t pdesc;
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 	pdesc = GET_BYTE(tp);	/* power description selector */
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	/* nominal supply voltage */
10330Sstevel@tonic-gate 	if (pdesc & CISTPL_CFTABLE_PD_NOMV) {
10340Sstevel@tonic-gate 		pd->nomV = cistpl_expd_parse(tp, &pd->nomV_flags) / 100;
10350Sstevel@tonic-gate 		pd->nomV_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS);
10360Sstevel@tonic-gate 	}
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	/* minimum supply voltage */
10390Sstevel@tonic-gate 	if (pdesc & CISTPL_CFTABLE_PD_MINV) {
10400Sstevel@tonic-gate 		pd->minV = cistpl_expd_parse(tp, &pd->minV_flags) / 100;
10410Sstevel@tonic-gate 		pd->minV_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS);
10420Sstevel@tonic-gate 	}
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	/* maximum supply voltage */
10450Sstevel@tonic-gate 	if (pdesc & CISTPL_CFTABLE_PD_MAXV) {
10460Sstevel@tonic-gate 		pd->maxV = cistpl_expd_parse(tp, &pd->maxV_flags) / 100;
10470Sstevel@tonic-gate 		pd->maxV_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS);
10480Sstevel@tonic-gate 	}
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	/* continuous supply current */
10510Sstevel@tonic-gate 	if (pdesc & CISTPL_CFTABLE_PD_STATICI) {
10520Sstevel@tonic-gate 		pd->staticI_flags |= CISTPL_CFTABLE_PD_MUL10;
10530Sstevel@tonic-gate 		pd->staticI = cistpl_expd_parse(tp, &pd->staticI_flags);
10540Sstevel@tonic-gate 		pd->staticI_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS);
10550Sstevel@tonic-gate 	}
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	/* maximum current required averaged over 1 second */
10580Sstevel@tonic-gate 	if (pdesc & CISTPL_CFTABLE_PD_AVGI) {
10590Sstevel@tonic-gate 		pd->avgI_flags |= CISTPL_CFTABLE_PD_MUL10;
10600Sstevel@tonic-gate 		pd->avgI = cistpl_expd_parse(tp, &pd->avgI_flags);
10610Sstevel@tonic-gate 		pd->avgI_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS);
10620Sstevel@tonic-gate 	}
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	/* maximum current required averaged over 10mS */
10650Sstevel@tonic-gate 	if (pdesc & CISTPL_CFTABLE_PD_PEAKI) {
10660Sstevel@tonic-gate 		pd->peakI_flags |= CISTPL_CFTABLE_PD_MUL10;
10670Sstevel@tonic-gate 		pd->peakI = cistpl_expd_parse(tp, &pd->peakI_flags);
10680Sstevel@tonic-gate 		pd->peakI_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS);
10690Sstevel@tonic-gate 	}
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	/* power down supply curent required */
10720Sstevel@tonic-gate 	if (pdesc & CISTPL_CFTABLE_PD_PDOWNI) {
10730Sstevel@tonic-gate 		pd->pdownI_flags |= CISTPL_CFTABLE_PD_MUL10;
10740Sstevel@tonic-gate 		pd->pdownI = cistpl_expd_parse(tp, &pd->pdownI_flags);
10750Sstevel@tonic-gate 		pd->pdownI_flags |= (pdesc | CISTPL_CFTABLE_PD_EXISTS);
10760Sstevel@tonic-gate 	}
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate /*
10800Sstevel@tonic-gate  * cistpl_expd_parse - read and parse an extended power description structure
10810Sstevel@tonic-gate  *
10820Sstevel@tonic-gate  *	cistpl_t *tp - pointer to pointer tuple data area
10830Sstevel@tonic-gate  *	int *flags - flags that get for this parameter:
10840Sstevel@tonic-gate  *			CISTPL_CFTABLE_PD_NC_SLEEP - no connection on
10850Sstevel@tonic-gate  *							sleep/power down
10860Sstevel@tonic-gate  *			CISTPL_CFTABLE_PD_ZERO - zero value required
10870Sstevel@tonic-gate  *			CISTPL_CFTABLE_PD_NC - no connection ever
10880Sstevel@tonic-gate  *
10890Sstevel@tonic-gate  * The power consumption is returned in the following units:
10900Sstevel@tonic-gate  *
10910Sstevel@tonic-gate  *				voltage - milliVOLTS
10920Sstevel@tonic-gate  *				current - microAMPS
10930Sstevel@tonic-gate  */
10940Sstevel@tonic-gate extern cistpl_pd_struct_t cistpl_pd_struct;
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate uint32_t
10970Sstevel@tonic-gate cistpl_expd_parse(cistpl_t *tp, uint32_t *flags)
10980Sstevel@tonic-gate {
10990Sstevel@tonic-gate 	cisdata_t pdesc;
11000Sstevel@tonic-gate 	uint32_t exponent, mantisa, val, digits = 0;
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	/*
11030Sstevel@tonic-gate 	 * Get the power description parameter byte and break it up
11040Sstevel@tonic-gate 	 *	into mantissa and exponent.
11050Sstevel@tonic-gate 	 */
11060Sstevel@tonic-gate 	pdesc = GET_BYTE(tp);
11070Sstevel@tonic-gate 	exponent = pdesc&7;
11080Sstevel@tonic-gate 	mantisa = (pdesc>>3)&0x0f;
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	if (pdesc & CISTPL_EXT_BIT) {
11110Sstevel@tonic-gate 		do {
11120Sstevel@tonic-gate 			if (LOOK_BYTE(tp) <= 0x63)
11130Sstevel@tonic-gate 				digits = LOOK_BYTE(tp);
11140Sstevel@tonic-gate 			if (LOOK_BYTE(tp) == CISTPL_CFTABLE_PD_NC_SLEEPM)
11150Sstevel@tonic-gate 				*flags |= CISTPL_CFTABLE_PD_NC_SLEEP;
11160Sstevel@tonic-gate 			if (LOOK_BYTE(tp) == CISTPL_CFTABLE_PD_ZEROM)
11170Sstevel@tonic-gate 				*flags |= CISTPL_CFTABLE_PD_ZERO;
11180Sstevel@tonic-gate 			if (LOOK_BYTE(tp) == CISTPL_CFTABLE_PD_NCM)
11190Sstevel@tonic-gate 				*flags |= CISTPL_CFTABLE_PD_NC;
11200Sstevel@tonic-gate 		} while (GET_BYTE(tp) & CISTPL_EXT_BIT);
11210Sstevel@tonic-gate 	}
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	val = CISTPL_PD_MAN(mantisa) * CISTPL_PD_EXP(exponent);
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 	/*
11260Sstevel@tonic-gate 	 * If we have to multiply the power value by ten, then just
11270Sstevel@tonic-gate 	 *	don't bother dividing.
11280Sstevel@tonic-gate 	 */
11290Sstevel@tonic-gate 	if (! (*flags & CISTPL_CFTABLE_PD_MUL10))
11300Sstevel@tonic-gate 		val = val/10;	/* do this since our mantissa table is X 10 */
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	/*
11330Sstevel@tonic-gate 	 * If we need to add some digits to the right of the decimal, do
11340Sstevel@tonic-gate 	 *	that here.
11350Sstevel@tonic-gate 	 */
11360Sstevel@tonic-gate 	if (exponent)
11370Sstevel@tonic-gate 		val = val + (digits * CISTPL_PD_EXP(exponent-1));
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	val /= 1000;
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	return (val);
11420Sstevel@tonic-gate }
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate /*
11450Sstevel@tonic-gate  * cistpl_devspeed - returns device speed in nS
11460Sstevel@tonic-gate  *
11470Sstevel@tonic-gate  *	cistpl_t *tp - tuple pointer.
11480Sstevel@tonic-gate  *	cisdata_t spindex - device speed table index
11490Sstevel@tonic-gate  *	int flags - operation flags
11500Sstevel@tonic-gate  *		CISTPL_DEVSPEED_TABLE:
11510Sstevel@tonic-gate  *		    Use the spindex argument as an index into a simple
11520Sstevel@tonic-gate  *			device speed table. ref: PCMCIA Release 2.01
11530Sstevel@tonic-gate  *			Card Metaformat pg. 5-14 table 5-12.
11540Sstevel@tonic-gate  *		    When this flag is set, the spindex argument is ignored.
11550Sstevel@tonic-gate  *		CISTPL_DEVSPEED_EXT:
11560Sstevel@tonic-gate  *		    Use the tp argument to access the
11570Sstevel@tonic-gate  *			tuple data area containing an extended speed
11580Sstevel@tonic-gate  *			code table.  ref: PCMCIA Release 2.01 Card
11590Sstevel@tonic-gate  *			Metaformat pg. 5-15 table 5-13.
11600Sstevel@tonic-gate  *		    The tp->read argument must point to the first byte of
11610Sstevel@tonic-gate  *			an extended speed code table.
11620Sstevel@tonic-gate  *		    When this flag is set, the spindex argument is
11630Sstevel@tonic-gate  *			used as a power-of-10 scale factor.  We only allow
11640Sstevel@tonic-gate  *			a maximum scale factor of 10^16.
11650Sstevel@tonic-gate  *
11660Sstevel@tonic-gate  * The device speed is returned in nS for all combinations of flags and
11670Sstevel@tonic-gate  *	speed table entries.
11680Sstevel@tonic-gate  *
11690Sstevel@tonic-gate  * Note if you pass the CISTPL_DEVSPEED_TABLE with a spindex index that
11700Sstevel@tonic-gate  *	refers to an extended speed table, you will get back an undefined
11710Sstevel@tonic-gate  *	speed value.
11720Sstevel@tonic-gate  */
11730Sstevel@tonic-gate extern cistpl_devspeed_struct_t cistpl_devspeed_struct;
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate uint32_t
11760Sstevel@tonic-gate cistpl_devspeed(cistpl_t *tp, cisdata_t spindex, uint32_t flags)
11770Sstevel@tonic-gate {
11780Sstevel@tonic-gate 	int scale = 1, first;
11790Sstevel@tonic-gate 	cisdata_t exspeed;
11800Sstevel@tonic-gate 	int exponent, mantisa;
11810Sstevel@tonic-gate 	uint32_t speed;
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	switch (flags) {
11840Sstevel@tonic-gate 	case CISTPL_DEVSPEED_TABLE:
11850Sstevel@tonic-gate 		speed = CISTPL_DEVSPEED_TBL(spindex);
11860Sstevel@tonic-gate 		break;
11870Sstevel@tonic-gate 	case CISTPL_DEVSPEED_EXT:
11880Sstevel@tonic-gate 		do {
11890Sstevel@tonic-gate 			exspeed = GET_BYTE(tp);
11900Sstevel@tonic-gate 			first = 1;
11910Sstevel@tonic-gate 			if (first) {
11920Sstevel@tonic-gate 				/*
11930Sstevel@tonic-gate 				 * XXX - ugh! we don't understand additional
11940Sstevel@tonic-gate 				 *	exspeed bytes
11950Sstevel@tonic-gate 				 */
11960Sstevel@tonic-gate 				first = 0;
11970Sstevel@tonic-gate 				exponent = (exspeed & 0x07);
11980Sstevel@tonic-gate 				mantisa = (exspeed >> 3) & 0x0f;
11990Sstevel@tonic-gate 				spindex &= 0x0f;	/* only allow 10^16 */
12000Sstevel@tonic-gate 				while (spindex--)
12010Sstevel@tonic-gate 					scale *= 10;
12020Sstevel@tonic-gate 			} /* if (first) */
12030Sstevel@tonic-gate 		} while (exspeed & CISTPL_EXT_BIT);
12040Sstevel@tonic-gate 		speed = scale * CISTPL_DEVSPEED_MAN(mantisa) *
12050Sstevel@tonic-gate 						CISTPL_DEVSPEED_EXP(exponent);
12060Sstevel@tonic-gate 		speed = speed/10;	/* XXX - mantissa table is all X 10 */
12070Sstevel@tonic-gate 		break;
12080Sstevel@tonic-gate 	default:
12090Sstevel@tonic-gate 		break;
12100Sstevel@tonic-gate 	}
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 	return (speed);
12130Sstevel@tonic-gate }
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate /*
12160Sstevel@tonic-gate  * cistpl_vers_2_handler - handler for the CISTPL_VERS_2 tuple
12170Sstevel@tonic-gate  *
12180Sstevel@tonic-gate  *	void *arg - points to a XXX where the information is stuffed into
12190Sstevel@tonic-gate  */
12200Sstevel@tonic-gate uint32_t
12210Sstevel@tonic-gate cistpl_vers_2_handler(cistpl_callout_t *co, cistpl_t *tp,
12220Sstevel@tonic-gate 					uint32_t flags, void *arg)
12230Sstevel@tonic-gate {
12240Sstevel@tonic-gate 	/*
12250Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
12260Sstevel@tonic-gate 	 *	generic handler for this
12270Sstevel@tonic-gate 	 */
12280Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
12290Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 	/*
12320Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
12330Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
12340Sstevel@tonic-gate 	 */
12350Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
12360Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
12390Sstevel@tonic-gate 		cistpl_vers_2_t *cs = (cistpl_vers_2_t *)arg;
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 		RESET_TP(tp);
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 		cs->vers = GET_BYTE(tp);
12440Sstevel@tonic-gate 		cs->comply = GET_BYTE(tp);
12450Sstevel@tonic-gate 		cs->dindex = GET_SHORT(tp);
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 		cs->reserved = GET_SHORT(tp);
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 		cs->vspec8 = GET_BYTE(tp);
12500Sstevel@tonic-gate 		cs->vspec9 = GET_BYTE(tp);
12510Sstevel@tonic-gate 		cs->nhdr = GET_BYTE(tp);
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 		(void) strcpy(cs->oem, cis_getstr(tp));
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 		if (GET_LEN(tp) > 0)
12560Sstevel@tonic-gate 		    (void) strcpy(cs->info, cis_getstr(tp));
12570Sstevel@tonic-gate 		else
12580Sstevel@tonic-gate 		    (void) strcpy(cs->info, "(no info)");
12590Sstevel@tonic-gate 	}
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
12620Sstevel@tonic-gate }
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate /*
12650Sstevel@tonic-gate  * cistpl_jedec_handler - handler for JEDEC C and JEDEC A tuples
12660Sstevel@tonic-gate  *
12670Sstevel@tonic-gate  *	void *arg - points to a XXX where the information is stuffed into
12680Sstevel@tonic-gate  */
12690Sstevel@tonic-gate uint32_t
12700Sstevel@tonic-gate cistpl_jedec_handler(cistpl_callout_t *co, cistpl_t *tp,
12710Sstevel@tonic-gate 					uint32_t flags, void *arg)
12720Sstevel@tonic-gate {
12730Sstevel@tonic-gate 	/*
12740Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
12750Sstevel@tonic-gate 	 *	generic handler for this
12760Sstevel@tonic-gate 	 */
12770Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
12780Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate 	/*
12810Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
12820Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
12830Sstevel@tonic-gate 	 */
12840Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
12850Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
12880Sstevel@tonic-gate 		int nid;
12890Sstevel@tonic-gate 		cistpl_jedec_t *cs = (cistpl_jedec_t *)arg;
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 		RESET_TP(tp);
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 		for (nid = 0; GET_LEN(tp) > 0 &&
12940Sstevel@tonic-gate 					nid < CISTPL_JEDEC_MAX_IDENTIFIERS &&
12950Sstevel@tonic-gate 					LOOK_BYTE(tp) != 0xFF; nid++) {
12960Sstevel@tonic-gate 			cs->jid[nid].id = GET_BYTE(tp);
12970Sstevel@tonic-gate 			cs->jid[nid].info = GET_BYTE(tp);
12980Sstevel@tonic-gate 		}
12990Sstevel@tonic-gate 		cs->nid = nid;
13000Sstevel@tonic-gate 	}
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
13030Sstevel@tonic-gate }
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate /*
13060Sstevel@tonic-gate  * cistpl_format_handler - handler for the CISTPL_FORMAT and
13070Sstevel@tonic-gate  *				CISTPL_FORMAT_A tuples
13080Sstevel@tonic-gate  */
13090Sstevel@tonic-gate uint32_t
13100Sstevel@tonic-gate cistpl_format_handler(cistpl_callout_t *co, cistpl_t *tp,
13110Sstevel@tonic-gate 					uint32_t flags, void *arg)
13120Sstevel@tonic-gate {
13130Sstevel@tonic-gate 	/*
13140Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
13150Sstevel@tonic-gate 	 *	generic handler for this
13160Sstevel@tonic-gate 	 */
13170Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
13180Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 	/*
13210Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
13220Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
13230Sstevel@tonic-gate 	 */
13240Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
13250Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
13280Sstevel@tonic-gate 		cistpl_format_t *cs = (cistpl_format_t *)arg;
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 		RESET_TP(tp);
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 		cs->type = GET_BYTE(tp);
13330Sstevel@tonic-gate 		cs->edc_length = LOOK_BYTE(tp) & EDC_LENGTH_MASK;
13340Sstevel@tonic-gate 		cs->edc_type = ((uint32_t)GET_BYTE(tp) >> EDC_TYPE_SHIFT) &
13350Sstevel@tonic-gate 								EDC_TYPE_MASK;
13360Sstevel@tonic-gate 		cs->offset = GET_LONG(tp);
13370Sstevel@tonic-gate 		cs->nbytes = GET_LONG(tp);
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate 		switch (cs->type) {
13400Sstevel@tonic-gate 		case TPLFMTTYPE_DISK:
13410Sstevel@tonic-gate 			cs->dev.disk.bksize = GET_SHORT(tp);
13420Sstevel@tonic-gate 			cs->dev.disk.nblocks = GET_LONG(tp);
13430Sstevel@tonic-gate 			cs->dev.disk.edcloc = GET_LONG(tp);
13440Sstevel@tonic-gate 			break;
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 		case TPLFMTTYPE_MEM:
13470Sstevel@tonic-gate 			cs->dev.mem.flags = GET_BYTE(tp);
13480Sstevel@tonic-gate 			cs->dev.mem.reserved = GET_BYTE(tp);
13490Sstevel@tonic-gate 			cs->dev.mem.address = (caddr_t)(uintptr_t)GET_LONG(tp);
13500Sstevel@tonic-gate 			cs->dev.disk.edcloc = GET_LONG(tp);
13510Sstevel@tonic-gate 			break;
13520Sstevel@tonic-gate 		default:
13530Sstevel@tonic-gate 			/* don't know about any other type */
13540Sstevel@tonic-gate 			break;
13550Sstevel@tonic-gate 		}
13560Sstevel@tonic-gate 	}
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
13590Sstevel@tonic-gate }
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate /*
13620Sstevel@tonic-gate  * cistpl_geometry_handler - handler for the CISTPL_GEOMETRY tuple
13630Sstevel@tonic-gate  *
13640Sstevel@tonic-gate  *	void *arg - points to a XXX where the information is stuffed into
13650Sstevel@tonic-gate  */
13660Sstevel@tonic-gate uint32_t
13670Sstevel@tonic-gate cistpl_geometry_handler(cistpl_callout_t *co, cistpl_t *tp, uint32_t flags,
13680Sstevel@tonic-gate 								void *arg)
13690Sstevel@tonic-gate {
13700Sstevel@tonic-gate 	/*
13710Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
13720Sstevel@tonic-gate 	 *	generic handler for this
13730Sstevel@tonic-gate 	 */
13740Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
13750Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 	/*
13780Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
13790Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
13800Sstevel@tonic-gate 	 */
13810Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
13820Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
13850Sstevel@tonic-gate 		cistpl_geometry_t *cs = (cistpl_geometry_t *)arg;
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 		RESET_TP(tp);
13880Sstevel@tonic-gate 		cs->spt = GET_BYTE(tp);
13890Sstevel@tonic-gate 		cs->tpc = GET_BYTE(tp);
13900Sstevel@tonic-gate 		cs->ncyl = GET_SHORT(tp);
13910Sstevel@tonic-gate 	}
13920Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
13930Sstevel@tonic-gate }
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate /*
13960Sstevel@tonic-gate  * cistpl_byteorder_handler - handler for the CISTPL_BYTEORDER tuple
13970Sstevel@tonic-gate  *
13980Sstevel@tonic-gate  *	void *arg - points to a XXX where the information is stuffed into
13990Sstevel@tonic-gate  */
14000Sstevel@tonic-gate uint32_t
14010Sstevel@tonic-gate cistpl_byteorder_handler(cistpl_callout_t *co, cistpl_t *tp, uint32_t flags,
14020Sstevel@tonic-gate 								void *arg)
14030Sstevel@tonic-gate {
14040Sstevel@tonic-gate 	/*
14050Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
14060Sstevel@tonic-gate 	 *	generic handler for this
14070Sstevel@tonic-gate 	 */
14080Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
14090Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	/*
14120Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
14130Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
14140Sstevel@tonic-gate 	 */
14150Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
14160Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
14190Sstevel@tonic-gate 		cistpl_byteorder_t *cs = (cistpl_byteorder_t *)arg;
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 		RESET_TP(tp);
14220Sstevel@tonic-gate 		cs->order = GET_BYTE(tp);
14230Sstevel@tonic-gate 		cs->map = GET_BYTE(tp);
14240Sstevel@tonic-gate 	}
14250Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
14260Sstevel@tonic-gate }
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate /*
14290Sstevel@tonic-gate  * cistpl_date_handler - handler for CISTPL_DATE card format tuple
14300Sstevel@tonic-gate  *
14310Sstevel@tonic-gate  *	void *arg - points to a cistpl_date_t * where the
14320Sstevel@tonic-gate  *			information is stuffed into
14330Sstevel@tonic-gate  */
14340Sstevel@tonic-gate uint32_t
14350Sstevel@tonic-gate cistpl_date_handler(cistpl_callout_t *co, cistpl_t *tp,
14360Sstevel@tonic-gate 					uint32_t flags, void *arg)
14370Sstevel@tonic-gate {
14380Sstevel@tonic-gate 	/*
14390Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
14400Sstevel@tonic-gate 	 *	generic handler for this
14410Sstevel@tonic-gate 	 */
14420Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
14430Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 	/*
14460Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
14470Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
14480Sstevel@tonic-gate 	 */
14490Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
14500Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
14510Sstevel@tonic-gate 
14520Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
14530Sstevel@tonic-gate 		cistpl_date_t *cs = (cistpl_date_t *)arg;
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate 		RESET_TP(tp);
14560Sstevel@tonic-gate 		cs->time = GET_SHORT(tp);
14570Sstevel@tonic-gate 		cs->day = GET_SHORT(tp);
14580Sstevel@tonic-gate 	}
14590Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
14600Sstevel@tonic-gate }
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate /*
14630Sstevel@tonic-gate  * cistpl_battery_handler - handler for CISTPL_BATTERY battery replacement
14640Sstevel@tonic-gate  *				date tuple
14650Sstevel@tonic-gate  *
14660Sstevel@tonic-gate  *	void *arg - points to a cistpl_battery_t * where the
14670Sstevel@tonic-gate  *			information is stuffed into
14680Sstevel@tonic-gate  */
14690Sstevel@tonic-gate uint32_t
14700Sstevel@tonic-gate cistpl_battery_handler(cistpl_callout_t *co, cistpl_t *tp,
14710Sstevel@tonic-gate 					uint32_t flags, void *arg)
14720Sstevel@tonic-gate {
14730Sstevel@tonic-gate 	/*
14740Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
14750Sstevel@tonic-gate 	 *	generic handler for this
14760Sstevel@tonic-gate 	 */
14770Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
14780Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 	/*
14810Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
14820Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
14830Sstevel@tonic-gate 	 */
14840Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
14850Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
14880Sstevel@tonic-gate 		cistpl_battery_t *cs = (cistpl_battery_t *)arg;
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 		RESET_TP(tp);
14910Sstevel@tonic-gate 		cs->rday = GET_SHORT(tp);
14920Sstevel@tonic-gate 		cs->xday = GET_SHORT(tp);
14930Sstevel@tonic-gate 	}
14940Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
14950Sstevel@tonic-gate }
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate /*
14980Sstevel@tonic-gate  * cistpl_org_handler - handler for CISTPL_ORG data organization tuple
14990Sstevel@tonic-gate  *
15000Sstevel@tonic-gate  *	void *arg - points to a cistpl_org_t * where the
15010Sstevel@tonic-gate  *			information is stuffed into
15020Sstevel@tonic-gate  */
15030Sstevel@tonic-gate uint32_t
15040Sstevel@tonic-gate cistpl_org_handler(cistpl_callout_t *co, cistpl_t *tp,
15050Sstevel@tonic-gate 					uint32_t flags, void *arg)
15060Sstevel@tonic-gate {
15070Sstevel@tonic-gate 	/*
15080Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
15090Sstevel@tonic-gate 	 *	generic handler for this
15100Sstevel@tonic-gate 	 */
15110Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
15120Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate 	/*
15150Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
15160Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
15170Sstevel@tonic-gate 	 */
15180Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
15190Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
15220Sstevel@tonic-gate 		cistpl_org_t *cs = (cistpl_org_t *)arg;
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 		RESET_TP(tp);
15250Sstevel@tonic-gate 		cs->type = GET_BYTE(tp);
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate 		(void) strcpy(cs->desc, cis_getstr(tp));
15280Sstevel@tonic-gate 	}
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
15310Sstevel@tonic-gate }
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate /*
15350Sstevel@tonic-gate  * cistpl_manfid_handler - handler for CISTPL_MANFID, the manufacturer ID tuple
15360Sstevel@tonic-gate  *
15370Sstevel@tonic-gate  *	void *arg - points to a XXX where the information is stuffed into
15380Sstevel@tonic-gate  */
15390Sstevel@tonic-gate uint32_t
15400Sstevel@tonic-gate cistpl_manfid_handler(cistpl_callout_t *co, cistpl_t *tp,
15410Sstevel@tonic-gate 					uint32_t flags, void *arg)
15420Sstevel@tonic-gate {
15430Sstevel@tonic-gate 	/*
15440Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
15450Sstevel@tonic-gate 	 *	generic handler for this
15460Sstevel@tonic-gate 	 */
15470Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
15480Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate 	/*
15510Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
15520Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
15530Sstevel@tonic-gate 	 */
15540Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
15550Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
15580Sstevel@tonic-gate 		cistpl_manfid_t *cs = (cistpl_manfid_t *)arg;
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate 		RESET_TP(tp);
15610Sstevel@tonic-gate 		cs->manf = GET_SHORT(tp);
15620Sstevel@tonic-gate 		cs->card = GET_SHORT(tp);
15630Sstevel@tonic-gate 	}
15640Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
15650Sstevel@tonic-gate }
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate /*
15680Sstevel@tonic-gate  * cistpl_funcid_handler - handler for CISTPL_FUNCID
15690Sstevel@tonic-gate  *
15700Sstevel@tonic-gate  *	void *arg - points to a XXX where the information is stuffed into
15710Sstevel@tonic-gate  */
15720Sstevel@tonic-gate uint32_t
15730Sstevel@tonic-gate cistpl_funcid_handler(cistpl_callout_t *co, cistpl_t *tp,
15740Sstevel@tonic-gate 					uint32_t flags, void *arg)
15750Sstevel@tonic-gate {
15760Sstevel@tonic-gate 	/*
15770Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
15780Sstevel@tonic-gate 	 *	generic handler for this
15790Sstevel@tonic-gate 	 */
15800Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
15810Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 	/*
15840Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
15850Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
15860Sstevel@tonic-gate 	 */
15870Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
15880Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
15910Sstevel@tonic-gate 		cistpl_funcid_t *cs = (cistpl_funcid_t *)arg;
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate 		RESET_TP(tp);
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 		cs->function = GET_BYTE(tp);
15960Sstevel@tonic-gate 		cs->sysinit = GET_BYTE(tp);
15970Sstevel@tonic-gate 	}
15980Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
15990Sstevel@tonic-gate }
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate /*
16030Sstevel@tonic-gate  * cistpl_funce_serial_handler - handler for the CISTPL_FUNCE/SERIAL tuple
16040Sstevel@tonic-gate  *
16050Sstevel@tonic-gate  *	void *arg - points to a XXX where the information is stuffed into
16060Sstevel@tonic-gate  */
16070Sstevel@tonic-gate uint32_t
16080Sstevel@tonic-gate cistpl_funce_serial_handler(cistpl_callout_t *co, cistpl_t *tp,
16090Sstevel@tonic-gate 						uint32_t flags, void *arg)
16100Sstevel@tonic-gate {
16110Sstevel@tonic-gate 	int subfunction;
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	/*
16140Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
16150Sstevel@tonic-gate 	 *	generic handler for this
16160Sstevel@tonic-gate 	 */
16170Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
16180Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
16190Sstevel@tonic-gate 
16200Sstevel@tonic-gate 	/*
16210Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
16220Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
16230Sstevel@tonic-gate 	 */
16240Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
16250Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
16280Sstevel@tonic-gate 		cistpl_funce_t *cs = (cistpl_funce_t *)arg;
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 		RESET_TP(tp);
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 		cs->function = TPLFUNC_SERIAL;
16330Sstevel@tonic-gate 		cs->subfunction = subfunction = GET_BYTE(tp);
16340Sstevel@tonic-gate 		switch (subfunction & 0xF) {
16350Sstevel@tonic-gate 		case TPLFE_SUB_SERIAL:
16360Sstevel@tonic-gate 		case TPLFE_CAP_SERIAL_DATA:
16370Sstevel@tonic-gate 		case TPLFE_CAP_SERIAL_FAX:
16380Sstevel@tonic-gate 		case TPLFE_CAP_SERIAL_VOICE:
16390Sstevel@tonic-gate 			cs->data.serial.ua = GET_BYTE(tp);
16400Sstevel@tonic-gate 			cs->data.serial.uc = GET_SHORT(tp);
16410Sstevel@tonic-gate 			break;
16420Sstevel@tonic-gate 		case TPLFE_SUB_MODEM_COMMON:
16430Sstevel@tonic-gate 		case TPLFE_CAP_MODEM_DATA:
16440Sstevel@tonic-gate 		case TPLFE_CAP_MODEM_FAX:
16450Sstevel@tonic-gate 		case TPLFE_CAP_MODEM_VOICE:
16460Sstevel@tonic-gate 			cs->data.modem.fc = GET_BYTE(tp);
16470Sstevel@tonic-gate 			cs->data.modem.cb = (GET_BYTE(tp) + 1) * 4;
16480Sstevel@tonic-gate 			cs->data.modem.eb = GET_INT24(tp);
16490Sstevel@tonic-gate 			cs->data.modem.tb = GET_INT24(tp);
16500Sstevel@tonic-gate 			break;
16510Sstevel@tonic-gate 		case TPLFE_SUB_MODEM_DATA:
16520Sstevel@tonic-gate 			cs->data.data_modem.ud = GET_BE_SHORT(tp) * 75;
16530Sstevel@tonic-gate 			cs->data.data_modem.ms = GET_SHORT(tp);
16540Sstevel@tonic-gate 			cs->data.data_modem.em = GET_BYTE(tp);
16550Sstevel@tonic-gate 			cs->data.data_modem.dc = GET_BYTE(tp);
16560Sstevel@tonic-gate 			cs->data.data_modem.cm = GET_BYTE(tp);
16570Sstevel@tonic-gate 			cs->data.data_modem.ex = GET_BYTE(tp);
16580Sstevel@tonic-gate 			cs->data.data_modem.dy = GET_BYTE(tp);
16590Sstevel@tonic-gate 			cs->data.data_modem.ef = GET_BYTE(tp);
16600Sstevel@tonic-gate 			for (cs->data.data_modem.ncd = 0;
16610Sstevel@tonic-gate 				GET_LEN(tp) > 0 && cs->data.data_modem.ncd < 16;
16620Sstevel@tonic-gate 						cs->data.data_modem.ncd++)
16630Sstevel@tonic-gate 				if (LOOK_BYTE(tp) != 255) {
16640Sstevel@tonic-gate 					cs->data.data_modem.cd[
16650Sstevel@tonic-gate 						cs->data.data_modem.ncd] =
16660Sstevel@tonic-gate 								GET_BYTE(tp);
16670Sstevel@tonic-gate 				} else {
16680Sstevel@tonic-gate 					GET_BYTE(tp);
16690Sstevel@tonic-gate 					break;
16700Sstevel@tonic-gate 				}
16710Sstevel@tonic-gate 			break;
16720Sstevel@tonic-gate 		case TPLFE_SUB_MODEM_FAX:
16730Sstevel@tonic-gate 			cs->data.fax.uf = GET_BE_SHORT(tp) * 75;
16740Sstevel@tonic-gate 			cs->data.fax.fm = GET_BYTE(tp);
16750Sstevel@tonic-gate 			cs->data.fax.fy = GET_BYTE(tp);
16760Sstevel@tonic-gate 			cs->data.fax.fs = GET_SHORT(tp);
16770Sstevel@tonic-gate 			for (cs->data.fax.ncf = 0;
16780Sstevel@tonic-gate 				GET_LEN(tp) > 0 && cs->data.fax.ncf < 16;
16790Sstevel@tonic-gate 							cs->data.fax.ncf++)
16800Sstevel@tonic-gate 				if (LOOK_BYTE(tp) != 255) {
16810Sstevel@tonic-gate 					cs->data.fax.cf[cs->data.fax.ncf] =
16820Sstevel@tonic-gate 								GET_BYTE(tp);
16830Sstevel@tonic-gate 				} else {
16840Sstevel@tonic-gate 					GET_BYTE(tp);
16850Sstevel@tonic-gate 					break;
16860Sstevel@tonic-gate 				}
16870Sstevel@tonic-gate 			break;
16880Sstevel@tonic-gate 		case TPLFE_SUB_VOICE:
16890Sstevel@tonic-gate 			cs->data.voice.uv = GET_BE_SHORT(tp) * 75;
16900Sstevel@tonic-gate 			for (cs->data.voice.nsr = 0; LOOK_BYTE(tp) != 0 &&
16910Sstevel@tonic-gate 				GET_LEN(tp) >= 2;
16920Sstevel@tonic-gate 						cs->data.voice.nsr++) {
16930Sstevel@tonic-gate 				cs->data.voice.sr[cs->data.voice.nsr] =
16940Sstevel@tonic-gate 					GET_BYTE(tp) * 1000;
16950Sstevel@tonic-gate 				cs->data.voice.sr[cs->data.voice.nsr] +=
16960Sstevel@tonic-gate 					GET_BYTE(tp) * 100;
16970Sstevel@tonic-gate 			}
16980Sstevel@tonic-gate 			for (cs->data.voice.nss = 0; LOOK_BYTE(tp) != 0 &&
16990Sstevel@tonic-gate 				GET_LEN(tp) >= 2;
17000Sstevel@tonic-gate 						cs->data.voice.nss++) {
17010Sstevel@tonic-gate 				cs->data.voice.ss[cs->data.voice.nss] =
17020Sstevel@tonic-gate 					GET_BYTE(tp) * 10;
17030Sstevel@tonic-gate 				cs->data.voice.ss[cs->data.voice.nss] +=
17040Sstevel@tonic-gate 								GET_BYTE(tp);
17050Sstevel@tonic-gate 			}
17060Sstevel@tonic-gate 			for (cs->data.voice.nsc = 0; LOOK_BYTE(tp) != 0 &&
17070Sstevel@tonic-gate 				GET_LEN(tp) >= 1;
17080Sstevel@tonic-gate 						cs->data.voice.nsc++) {
17090Sstevel@tonic-gate 				cs->data.voice.sc[cs->data.voice.nsc] =
17100Sstevel@tonic-gate 								GET_BYTE(tp);
17110Sstevel@tonic-gate 			}
17120Sstevel@tonic-gate 			break;
17130Sstevel@tonic-gate 		default:
17140Sstevel@tonic-gate 			break;
17150Sstevel@tonic-gate 		}
17160Sstevel@tonic-gate 	}
17170Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
17180Sstevel@tonic-gate }
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate /*
17210Sstevel@tonic-gate  * cistpl_funce_lan_handler - handler for the CISTPL_FUNCE/LAN tuple
17220Sstevel@tonic-gate  *
17230Sstevel@tonic-gate  *	void *arg - points to a XXX where the information is stuffed into
17240Sstevel@tonic-gate  */
17250Sstevel@tonic-gate uint32_t
17260Sstevel@tonic-gate cistpl_funce_lan_handler(cistpl_callout_t *co, cistpl_t *tp, uint32_t flags,
17270Sstevel@tonic-gate 								void *arg)
17280Sstevel@tonic-gate {
17290Sstevel@tonic-gate 	int subfunction;
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	/*
17320Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
17330Sstevel@tonic-gate 	 *	generic handler for this
17340Sstevel@tonic-gate 	 */
17350Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
17360Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate 	/*
17390Sstevel@tonic-gate 	 * We don't currently validate this tuple. This call will
17400Sstevel@tonic-gate 	 *	always set tp->flags |= CISTPLF_VALID.
17410Sstevel@tonic-gate 	 */
17420Sstevel@tonic-gate 	if (flags & HANDTPL_COPY_DONE)
17430Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate 	if (flags & HANDTPL_PARSE_LTUPLE) {
17460Sstevel@tonic-gate 		int i;
17470Sstevel@tonic-gate 		cistpl_funce_t *cs = (cistpl_funce_t *)arg;
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 		RESET_TP(tp);
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate 		cs->function = TPLFUNC_LAN;
17520Sstevel@tonic-gate 		cs->subfunction = subfunction = GET_BYTE(tp);
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate 		switch (subfunction) {
17550Sstevel@tonic-gate 		case TPLFE_NETWORK_INFO:
17560Sstevel@tonic-gate 			cs->data.lan.tech = GET_BYTE(tp);
17570Sstevel@tonic-gate 			cs->data.lan.speed = GET_BYTE(tp);
17580Sstevel@tonic-gate 			i = GET_BYTE(tp);
17590Sstevel@tonic-gate 			if (i < 24) {
17600Sstevel@tonic-gate 				cs->data.lan.speed <<= i;
17610Sstevel@tonic-gate 			} else {
17620Sstevel@tonic-gate 				/*
17630Sstevel@tonic-gate 				 * if speed is too large a value
17640Sstevel@tonic-gate 				 * to hold in a uint32 flag it and
17650Sstevel@tonic-gate 				 * store as [mantissa][exponent]
17660Sstevel@tonic-gate 				 * in least significant 16 bits
17670Sstevel@tonic-gate 				 */
17680Sstevel@tonic-gate 				cs->data.lan.speed = 0x80000000 |
17690Sstevel@tonic-gate 					(cs->data.lan.speed << 8) | i;
17700Sstevel@tonic-gate 			}
17710Sstevel@tonic-gate 			cs->data.lan.media = GET_BYTE(tp);
17720Sstevel@tonic-gate 			cs->data.lan.con = GET_BYTE(tp);
17730Sstevel@tonic-gate 			cs->data.lan.id_sz = GET_BYTE(tp);
17740Sstevel@tonic-gate 			if (cs->data.lan.id_sz <= 16) {
17750Sstevel@tonic-gate 				for (i = 0; i < cs->data.lan.id_sz; i++)
17760Sstevel@tonic-gate 					cs->data.lan.id[i] = GET_BYTE(tp);
17770Sstevel@tonic-gate 			}
17780Sstevel@tonic-gate 			break;
17790Sstevel@tonic-gate 		default:
17800Sstevel@tonic-gate 				/* unknown LAN tuple type */
17810Sstevel@tonic-gate 			return (CISTPLF_UNKNOWN);
17820Sstevel@tonic-gate 		}
17830Sstevel@tonic-gate 	}
17840Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
17850Sstevel@tonic-gate }
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate /*
17880Sstevel@tonic-gate  * cistpl_linktarget_handler - handler for CISTPL_LINKTARGET tuple
17890Sstevel@tonic-gate  *
17900Sstevel@tonic-gate  *	void *arg - points to a cistpl_linktarget_t * where the
17910Sstevel@tonic-gate  *			information is stuffed into
17920Sstevel@tonic-gate  *
17930Sstevel@tonic-gate  *	If HANDTPL_COPY_DONE is set, we just validate the tuple but
17940Sstevel@tonic-gate  *		do not return any values.
17950Sstevel@tonic-gate  *	If HANDTPL_PARSE_LTUPLE is set, we validate the tuple and
17960Sstevel@tonic-gate  *		return the parsed tuple data if the tuple is valid.
17970Sstevel@tonic-gate  *
17980Sstevel@tonic-gate  *	If the tuple link field is invalid, the CISTPLF_LINK_INVALID flag
17990Sstevel@tonic-gate  *		will be set in the tp->flags field and HANDTPL_ERROR
18000Sstevel@tonic-gate  *		will be returned.
18010Sstevel@tonic-gate  *
18020Sstevel@tonic-gate  *	If the tuple data body is invalid, the CISTPLF_PARAMS_INVALID flag
18030Sstevel@tonic-gate  *		will be set in the tp->flags field and HANDTPL_ERROR
18040Sstevel@tonic-gate  *		will be returned.
18050Sstevel@tonic-gate  *
18060Sstevel@tonic-gate  *	The tuple is considered invalid if it's link field is less than
18070Sstevel@tonic-gate  *		MIN_LINKTARGET_LENGTH or if the data body of the tuple
18080Sstevel@tonic-gate  *		does not contain the pattern CISTPL_LINKTARGET_MAGIC.
18090Sstevel@tonic-gate  *
18100Sstevel@tonic-gate  * XXX At some point we should revisit this to see if we can call
18110Sstevel@tonic-gate  *	cis_validate_longlink_acm instead of doing the validation
18120Sstevel@tonic-gate  *	in both places.
18130Sstevel@tonic-gate  */
18140Sstevel@tonic-gate uint32_t
18150Sstevel@tonic-gate cistpl_linktarget_handler(cistpl_callout_t *co, cistpl_t *tp, uint32_t flags,
18160Sstevel@tonic-gate 								void *arg)
18170Sstevel@tonic-gate {
18180Sstevel@tonic-gate 	/*
18190Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
18200Sstevel@tonic-gate 	 *	generic handler for this
18210Sstevel@tonic-gate 	 */
18220Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
18230Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate 	/*
18260Sstevel@tonic-gate 	 * Validate the tuple for both the HANDTPL_COPY_DONE case and
18270Sstevel@tonic-gate 	 *	the HANDTPL_PARSE_LTUPLE case. Only return data in
18280Sstevel@tonic-gate 	 *	the HANDTPL_PARSE_LTUPLE case.
18290Sstevel@tonic-gate 	 */
18300Sstevel@tonic-gate 	if (flags & (HANDTPL_COPY_DONE | HANDTPL_PARSE_LTUPLE)) {
18310Sstevel@tonic-gate 		uchar_t *cp;
18320Sstevel@tonic-gate 		cisdata_t tl;
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate 		if ((tl = tp->len) >= (cisdata_t)MIN_LINKTARGET_LENGTH) {
18350Sstevel@tonic-gate 			cisdata_t *ltm = (cisdata_t *)CISTPL_LINKTARGET_MAGIC;
18360Sstevel@tonic-gate 			int i;
18370Sstevel@tonic-gate 
18380Sstevel@tonic-gate 			RESET_TP(tp);
18390Sstevel@tonic-gate 
18400Sstevel@tonic-gate 			/*
18410Sstevel@tonic-gate 			 * Save the start address of this string in case
18420Sstevel@tonic-gate 			 *	the tuple turns out to be OK since we
18430Sstevel@tonic-gate 			 *	need to pass this address to the caller.
18440Sstevel@tonic-gate 			 */
18450Sstevel@tonic-gate 			cp = GET_BYTE_ADDR(tp);
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 			/*
18480Sstevel@tonic-gate 			 * Check each byte of the tuple body to see if it
18490Sstevel@tonic-gate 			 *	matches what should be in a valid tuple.
18500Sstevel@tonic-gate 			 *	Note that we can't assume that this magic
18510Sstevel@tonic-gate 			 *	pattern is a string and we also only need
18520Sstevel@tonic-gate 			 *	to be sure that MIN_LINKTARGET_LENGTH bytes
18530Sstevel@tonic-gate 			 *	match; all bytes following this magic number
18540Sstevel@tonic-gate 			 *	in this tuple are ignored.
18550Sstevel@tonic-gate 			 */
18560Sstevel@tonic-gate 			for (i = 0; i < MIN_LINKTARGET_LENGTH; i++) {
18570Sstevel@tonic-gate 				if (GET_BYTE(tp) != *ltm++) {
18580Sstevel@tonic-gate 					tp->flags |= CISTPLF_PARAMS_INVALID;
18590Sstevel@tonic-gate 					return (HANDTPL_ERROR);
18600Sstevel@tonic-gate 				}
18610Sstevel@tonic-gate 			} /* MIN_LINKTARGET_LENGTH */
18620Sstevel@tonic-gate 
18630Sstevel@tonic-gate 			/*
18640Sstevel@tonic-gate 			 * This tuple is valid.
18650Sstevel@tonic-gate 			 */
18660Sstevel@tonic-gate 			if (flags & HANDTPL_COPY_DONE)
18670Sstevel@tonic-gate 				tp->flags |= CISTPLF_VALID;
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 			/*
18700Sstevel@tonic-gate 			 * If we're also parsing this tuple, then
18710Sstevel@tonic-gate 			 *	setup the return values.
18720Sstevel@tonic-gate 			 */
18730Sstevel@tonic-gate 			if (flags & HANDTPL_PARSE_LTUPLE) {
18740Sstevel@tonic-gate 				cistpl_linktarget_t *cs =
18750Sstevel@tonic-gate 						(cistpl_linktarget_t *)arg;
18760Sstevel@tonic-gate 
18770Sstevel@tonic-gate 				cs->length = tl;
18780Sstevel@tonic-gate 				(void) strncpy(cs->tpltg_tag, (char *)cp,
18790Sstevel@tonic-gate 								cs->length);
18800Sstevel@tonic-gate 				cs->tpltg_tag[cs->length] = NULL;
18810Sstevel@tonic-gate 
18820Sstevel@tonic-gate 			} /* HANDTPL_PARSE_LTUPLE */
18830Sstevel@tonic-gate 
18840Sstevel@tonic-gate 		} else {
18850Sstevel@tonic-gate 
18860Sstevel@tonic-gate 			tp->flags |= CISTPLF_LINK_INVALID;
18870Sstevel@tonic-gate 			return (HANDTPL_ERROR);
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate 		} /* CISTPL_LINKTARGET */
18900Sstevel@tonic-gate 
18910Sstevel@tonic-gate 	} /* (HANDTPL_COPY_DONE | HANDTPL_PARSE_LTUPLE) */
18920Sstevel@tonic-gate 
18930Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
18940Sstevel@tonic-gate }
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate /*
18970Sstevel@tonic-gate  * cistpl_longlink_ac_handler - handler for CISTPL_LONGLINK_A and
18980Sstevel@tonic-gate  *				CISTPL_LONGLINK_C tuples
18990Sstevel@tonic-gate  *
19000Sstevel@tonic-gate  *	void *arg - points to a cistpl_longlink_ac_t * where the
19010Sstevel@tonic-gate  *			information is stuffed into
19020Sstevel@tonic-gate  *
19030Sstevel@tonic-gate  *	If the passed in tuple is CISTPL_LONGLINK_A the CISTPL_LONGLINK_AC_AM
19040Sstevel@tonic-gate  *		flag in cistpl_longlink_ac_t->flags is set.
19050Sstevel@tonic-gate  *	If the passed in tuple is CISTPL_LONGLINK_C the CISTPL_LONGLINK_AC_CM
19060Sstevel@tonic-gate  *		flag in cistpl_longlink_ac_t->flags is set.
19070Sstevel@tonic-gate  *
19080Sstevel@tonic-gate  *	If HANDTPL_COPY_DONE is set, we just validate the tuple but
19090Sstevel@tonic-gate  *		do not return any values.
19100Sstevel@tonic-gate  *	If HANDTPL_PARSE_LTUPLE is set, we validate the tuple and
19110Sstevel@tonic-gate  *		return the parsed tuple data if the tuple is valid.
19120Sstevel@tonic-gate  *
19130Sstevel@tonic-gate  *	If the tuple link field is invalid, the CISTPLF_LINK_INVALID flag
19140Sstevel@tonic-gate  *		will be set in the tp->flags field and HANDTPL_ERROR
19150Sstevel@tonic-gate  *		will be returned.
19160Sstevel@tonic-gate  *
19170Sstevel@tonic-gate  *	The tuple is considered invalid if it's link field is less than
19180Sstevel@tonic-gate  *		MIN_LONGLINK_AC_LENGTH.
19190Sstevel@tonic-gate  */
19200Sstevel@tonic-gate uint32_t
19210Sstevel@tonic-gate cistpl_longlink_ac_handler(cistpl_callout_t *co, cistpl_t *tp, uint32_t flags,
19220Sstevel@tonic-gate 								void *arg)
19230Sstevel@tonic-gate {
19240Sstevel@tonic-gate 	/*
19250Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
19260Sstevel@tonic-gate 	 *	generic handler for this
19270Sstevel@tonic-gate 	 */
19280Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
19290Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate 	/*
19320Sstevel@tonic-gate 	 * Validate the tuple for both the HANDTPL_COPY_DONE case and
19330Sstevel@tonic-gate 	 *	the HANDTPL_PARSE_LTUPLE case. Only return data in
19340Sstevel@tonic-gate 	 *	the HANDTPL_PARSE_LTUPLE case.
19350Sstevel@tonic-gate 	 */
19360Sstevel@tonic-gate 	if (flags & (HANDTPL_COPY_DONE | HANDTPL_PARSE_LTUPLE)) {
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate 		if (tp->len >= (cisdata_t)MIN_LONGLINK_AC_LENGTH) {
19390Sstevel@tonic-gate 
19400Sstevel@tonic-gate 			/*
19410Sstevel@tonic-gate 			 * This tuple is valid.
19420Sstevel@tonic-gate 			 */
19430Sstevel@tonic-gate 			if (flags & HANDTPL_COPY_DONE)
19440Sstevel@tonic-gate 				tp->flags |= CISTPLF_VALID;
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 			if (flags & HANDTPL_PARSE_LTUPLE) {
19470Sstevel@tonic-gate 				cistpl_longlink_ac_t *cs =
19480Sstevel@tonic-gate 						(cistpl_longlink_ac_t *)arg;
19490Sstevel@tonic-gate 
19500Sstevel@tonic-gate 				switch (tp->type) {
19510Sstevel@tonic-gate 				    case CISTPL_LONGLINK_A:
19520Sstevel@tonic-gate 					cs->flags = CISTPL_LONGLINK_AC_AM;
19530Sstevel@tonic-gate 					break;
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 				    case CISTPL_LONGLINK_C:
19560Sstevel@tonic-gate 					cs->flags = CISTPL_LONGLINK_AC_CM;
19570Sstevel@tonic-gate 					break;
19580Sstevel@tonic-gate 				    default:
19590Sstevel@tonic-gate 					break;
19600Sstevel@tonic-gate 				} /* switch */
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate 				RESET_TP(tp);
19630Sstevel@tonic-gate 
19640Sstevel@tonic-gate 				cs->tpll_addr = GET_LONG(tp);
19650Sstevel@tonic-gate 
19660Sstevel@tonic-gate 			} /* HANDTPL_PARSE_LTUPLE */
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate 		} else {
19690Sstevel@tonic-gate 			tp->flags |= CISTPLF_LINK_INVALID;
19700Sstevel@tonic-gate 			return (HANDTPL_ERROR);
19710Sstevel@tonic-gate 		} /* MIN_LONGLINK_AC_LENGTH */
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate 	} /* (HANDTPL_COPY_DONE | HANDTPL_PARSE_LTUPLE) */
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
19760Sstevel@tonic-gate }
19770Sstevel@tonic-gate 
19780Sstevel@tonic-gate /*
19790Sstevel@tonic-gate  * cistpl_longlink_mfc_handler - handler for CISTPL_LONGLINK_MFC tuples
19800Sstevel@tonic-gate  *
19810Sstevel@tonic-gate  *	void *arg - points to a cistpl_longlink_mfc_t * where the
19820Sstevel@tonic-gate  *			information is stuffed into
19830Sstevel@tonic-gate  *
19840Sstevel@tonic-gate  *	If HANDTPL_COPY_DONE is set, we just validate the tuple but
19850Sstevel@tonic-gate  *		do not return any values.
19860Sstevel@tonic-gate  *	If HANDTPL_PARSE_LTUPLE is set, we validate the tuple and
19870Sstevel@tonic-gate  *		return the parsed tuple data if the tuple is valid.
19880Sstevel@tonic-gate  *
19890Sstevel@tonic-gate  *	If the tuple link field is invalid, the CISTPLF_LINK_INVALID flag
19900Sstevel@tonic-gate  *		will be set in the tp->flags field and HANDTPL_ERROR
19910Sstevel@tonic-gate  *		will be returned.
19920Sstevel@tonic-gate  *
19930Sstevel@tonic-gate  *	If the number of register sets is invalid, the CISTPLF_PARAMS_INVALID
19940Sstevel@tonic-gate  *		flag be set in the tp->flags field and HANDTPL_ERROR will be
19950Sstevel@tonic-gate  *		returned.
19960Sstevel@tonic-gate  *
19970Sstevel@tonic-gate  *	The tuple is considered invalid if it's link field is less than
19980Sstevel@tonic-gate  *		MIN_LONGLINK_MFC_LENGTH or if the number of register sets
19990Sstevel@tonic-gate  *		is not in the range [MIN_LONGLINK_MFC_NREGS..CIS_MAX_FUNCTIONS]
20000Sstevel@tonic-gate  */
20010Sstevel@tonic-gate uint32_t
20020Sstevel@tonic-gate cistpl_longlink_mfc_handler(cistpl_callout_t *co, cistpl_t *tp,
20030Sstevel@tonic-gate 					uint32_t flags, void *arg)
20040Sstevel@tonic-gate {
20050Sstevel@tonic-gate 	/*
20060Sstevel@tonic-gate 	 * nothing special about our flags, so just call the
20070Sstevel@tonic-gate 	 *	generic handler for this
20080Sstevel@tonic-gate 	 */
20090Sstevel@tonic-gate 	if (flags & HANDTPL_SET_FLAGS)
20100Sstevel@tonic-gate 		return (cis_no_tuple_handler(co, tp, flags, arg));
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 	/*
20130Sstevel@tonic-gate 	 * Validate the tuple for both the HANDTPL_COPY_DONE case and
20140Sstevel@tonic-gate 	 *	the HANDTPL_PARSE_LTUPLE case. Only return data in
20150Sstevel@tonic-gate 	 *	the HANDTPL_PARSE_LTUPLE case.
20160Sstevel@tonic-gate 	 */
20170Sstevel@tonic-gate 	if (flags & (HANDTPL_COPY_DONE | HANDTPL_PARSE_LTUPLE)) {
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate 		if (tp->len >= (cisdata_t)MIN_LONGLINK_MFC_LENGTH) {
20200Sstevel@tonic-gate 
20210Sstevel@tonic-gate 			/*
20220Sstevel@tonic-gate 			 * This tuple is valid.
20230Sstevel@tonic-gate 			 */
20240Sstevel@tonic-gate 			if (flags & HANDTPL_COPY_DONE)
20250Sstevel@tonic-gate 				tp->flags |= CISTPLF_VALID;
20260Sstevel@tonic-gate 
20270Sstevel@tonic-gate 			if (flags & HANDTPL_PARSE_LTUPLE) {
20280Sstevel@tonic-gate 				cistpl_longlink_mfc_t *cs =
20290Sstevel@tonic-gate 						(cistpl_longlink_mfc_t *)arg;
20300Sstevel@tonic-gate 				int fn;
20310Sstevel@tonic-gate 
20320Sstevel@tonic-gate 				RESET_TP(tp);
20330Sstevel@tonic-gate 
20340Sstevel@tonic-gate 				/*
20350Sstevel@tonic-gate 				 * Get the number of register sets described
20360Sstevel@tonic-gate 				 *	by this tuple. The number of register
20370Sstevel@tonic-gate 				 *	sets must be greter than or equal to
20380Sstevel@tonic-gate 				 *	MIN_LONGLINK_MFC_NREGS and less than
20390Sstevel@tonic-gate 				 *	CIS_MAX_FUNCTIONS.
20400Sstevel@tonic-gate 				 * Note that the number of functions is equal
20410Sstevel@tonic-gate 				 *	to the number of register sets.
20420Sstevel@tonic-gate 				 */
20430Sstevel@tonic-gate 				cs->nregs = GET_BYTE(tp);
20440Sstevel@tonic-gate 				cs->nfuncs = cs->nregs;
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 				if ((cs->nregs < MIN_LONGLINK_MFC_NREGS) ||
20470Sstevel@tonic-gate 					(cs->nregs > CIS_MAX_FUNCTIONS)) {
20480Sstevel@tonic-gate 				    tp->flags |= CISTPLF_PARAMS_INVALID;
20490Sstevel@tonic-gate 				    return (HANDTPL_ERROR);
20500Sstevel@tonic-gate 				}
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 				/*
20530Sstevel@tonic-gate 				 * Cycle through each function and setup
20540Sstevel@tonic-gate 				 *	the appropriate parameter values.
20550Sstevel@tonic-gate 				 */
20560Sstevel@tonic-gate 				for (fn = 0; fn < cs->nregs; fn++) {
20570Sstevel@tonic-gate 				    cs->function[fn].tas = GET_BYTE(tp);
20580Sstevel@tonic-gate 				    cs->function[fn].addr = GET_LONG(tp);
20590Sstevel@tonic-gate 				} /* for (fn) */
20600Sstevel@tonic-gate 
20610Sstevel@tonic-gate 			} /* HANDTPL_PARSE_LTUPLE */
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 		} else {
20640Sstevel@tonic-gate 			tp->flags |= CISTPLF_LINK_INVALID;
20650Sstevel@tonic-gate 			return (HANDTPL_ERROR);
20660Sstevel@tonic-gate 		} /* MIN_LONGLINK_MFC_LENGTH */
20670Sstevel@tonic-gate 
20680Sstevel@tonic-gate 	} /* (HANDTPL_COPY_DONE | HANDTPL_PARSE_LTUPLE) */
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate 	return (CISTPLF_NOERROR);
20710Sstevel@tonic-gate }
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate /*
20740Sstevel@tonic-gate  * cis_validate_longlink_acm - Validates the secondary tuple chain pointed
20750Sstevel@tonic-gate  *				to by cisptr and specified by a previous
20760Sstevel@tonic-gate  *				CISTPL_LONGLINK_A, CISTPL_LONGLINK_C or
20770Sstevel@tonic-gate  *				CISTPL_LONGLINK_MFC tuple.
20780Sstevel@tonic-gate  *
20790Sstevel@tonic-gate  *	cisptr->offset must be the offset to the first byte in the secondary
20800Sstevel@tonic-gate  *		tuple chain to validate
20810Sstevel@tonic-gate  *	cisptr->flags must be setup to specify the correct address space
20820Sstevel@tonic-gate  *
20830Sstevel@tonic-gate  * The cisptr->offset member is not updated after this function returns.
20840Sstevel@tonic-gate  *
20850Sstevel@tonic-gate  *	BAD_CIS_ADDR is returned is the raw CIS data cound not be read.
20860Sstevel@tonic-gate  *	HANDTPL_ERROR is returned if the secondary tuple chain does not
20870Sstevel@tonic-gate  *		contain a valid CISTPL_LINKTARGET tuple.
20880Sstevel@tonic-gate  */
20890Sstevel@tonic-gate uint32_t
20900Sstevel@tonic-gate cis_validate_longlink_acm(cisptr_t *cisptr)
20910Sstevel@tonic-gate {
20920Sstevel@tonic-gate 	uchar_t cb[MIN_LINKTARGET_LENGTH + LINKTARGET_AC_HEADER_LENGTH];
20930Sstevel@tonic-gate 	cisptr_t t_cisptr, *cpt;
20940Sstevel@tonic-gate 	int tl;
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate 	/*
20970Sstevel@tonic-gate 	 * Since the NEXT_CIS_ADDR macro increments the cisptr_t->offset
20980Sstevel@tonic-gate 	 *	member, make a local copy of the cisptr and use the local
20990Sstevel@tonic-gate 	 *	copy to read data from the card.
21000Sstevel@tonic-gate 	 */
21010Sstevel@tonic-gate 	cpt = &t_cisptr;
21020Sstevel@tonic-gate 	bcopy((caddr_t)cisptr, (caddr_t)cpt, sizeof (cisptr_t));
21030Sstevel@tonic-gate 
21040Sstevel@tonic-gate 	for (tl = 0; tl < MIN_LINKTARGET_LENGTH +
21050Sstevel@tonic-gate 					LINKTARGET_AC_HEADER_LENGTH; tl++) {
21060Sstevel@tonic-gate 
21070Sstevel@tonic-gate 		cb[tl] = GET_CIS_DATA(cpt);
21080Sstevel@tonic-gate 		if (!NEXT_CIS_ADDR(cpt))
21090Sstevel@tonic-gate 			return ((uint32_t)BAD_CIS_ADDR);
21100Sstevel@tonic-gate 
21110Sstevel@tonic-gate 	} /* for */
21120Sstevel@tonic-gate 
21130Sstevel@tonic-gate 	if ((cb[0] == CISTPL_LINKTARGET) && (cb[1] >= MIN_LINKTARGET_LENGTH)) {
21140Sstevel@tonic-gate 		cisdata_t *ltm = (cisdata_t *)CISTPL_LINKTARGET_MAGIC;
21150Sstevel@tonic-gate 
21160Sstevel@tonic-gate 		for (tl = 0; tl < MIN_LINKTARGET_LENGTH; tl++, ltm++) {
21170Sstevel@tonic-gate 			if (cb[tl + LINKTARGET_AC_HEADER_LENGTH] != *ltm)
21180Sstevel@tonic-gate 				return (HANDTPL_ERROR);
21190Sstevel@tonic-gate 		}
21200Sstevel@tonic-gate 		return (CISTPLF_NOERROR);
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate 	} /* if */
21230Sstevel@tonic-gate 
21240Sstevel@tonic-gate 	return (HANDTPL_ERROR);
21250Sstevel@tonic-gate }
21260Sstevel@tonic-gate 
21270Sstevel@tonic-gate /*
21280Sstevel@tonic-gate  * cis_getstr (tp)
21290Sstevel@tonic-gate  *	we want the address of the first character returned
21300Sstevel@tonic-gate  *	but need to skip past the string in the cistpl_t structure
21310Sstevel@tonic-gate  */
21320Sstevel@tonic-gate char *
21330Sstevel@tonic-gate cis_getstr(cistpl_t *tp)
21340Sstevel@tonic-gate {
21350Sstevel@tonic-gate 	uchar_t *cp, *cpp;
21360Sstevel@tonic-gate 	uchar_t x;
21370Sstevel@tonic-gate 
21380Sstevel@tonic-gate 	cp = tp->read.byte;
21390Sstevel@tonic-gate 	cpp = cp;
21400Sstevel@tonic-gate 
21410Sstevel@tonic-gate 	while ((x = LOOK_BYTE(tp)) != 0 && x != 0xff) {
21420Sstevel@tonic-gate 		x = GET_BYTE(tp);
21430Sstevel@tonic-gate 	}
21440Sstevel@tonic-gate 
21450Sstevel@tonic-gate 	(void) GET_BYTE(tp);	/* get past that last byte */
21460Sstevel@tonic-gate 
21470Sstevel@tonic-gate 	while ((*cpp != 0) && (*cpp != 0xff))
21480Sstevel@tonic-gate 	    cpp++;
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate 	*cpp = NULL;
21510Sstevel@tonic-gate 
21520Sstevel@tonic-gate 	return ((char *)cp);
21530Sstevel@tonic-gate }
21540Sstevel@tonic-gate 
21550Sstevel@tonic-gate /*
21560Sstevel@tonic-gate  * cis_return_name - returns name of tuple
21570Sstevel@tonic-gate  *
21580Sstevel@tonic-gate  *    calling:	co - pointer to cistpl_callout_t entry that contains
21590Sstevel@tonic-gate  *			tuple name to return
21600Sstevel@tonic-gate  *		gtn - pointer to cistpl_get_tuple_name_t to return
21610Sstevel@tonic-gate  *			name into
21620Sstevel@tonic-gate  */
21630Sstevel@tonic-gate static void
21640Sstevel@tonic-gate cis_return_name(cistpl_callout_t *co, cistpl_get_tuple_name_t *gtn)
21650Sstevel@tonic-gate {
21660Sstevel@tonic-gate 	(void) strncpy(gtn->name, co->text, CIS_MAX_TUPLE_NAME_LEN);
21670Sstevel@tonic-gate 	gtn->name[CIS_MAX_TUPLE_NAME_LEN - 1] = NULL;
21680Sstevel@tonic-gate }
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate /*
21710Sstevel@tonic-gate  * cis_malloc/cis_free
21720Sstevel@tonic-gate  *	wrappers around kmem_alloc()/kmem_free() that
21730Sstevel@tonic-gate  *	provide malloc/free style usage
21740Sstevel@tonic-gate  */
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate caddr_t
21770Sstevel@tonic-gate cis_malloc(size_t len)
21780Sstevel@tonic-gate {
21790Sstevel@tonic-gate 	caddr_t addr;
21800Sstevel@tonic-gate 
21810Sstevel@tonic-gate 	addr = kmem_zalloc(len + sizeof (size_t), KM_SLEEP);
21820Sstevel@tonic-gate 	*(size_t *)addr = len + sizeof (size_t);
21830Sstevel@tonic-gate 	addr += sizeof (size_t);
21840Sstevel@tonic-gate 	return (addr);
21850Sstevel@tonic-gate }
21860Sstevel@tonic-gate 
21870Sstevel@tonic-gate void
21880Sstevel@tonic-gate cis_free(caddr_t addr)
21890Sstevel@tonic-gate {
21900Sstevel@tonic-gate 	size_t len;
21910Sstevel@tonic-gate 	addr -= sizeof (size_t);
21920Sstevel@tonic-gate 	len = *(size_t *)addr;
21930Sstevel@tonic-gate 	kmem_free(addr, len);
21940Sstevel@tonic-gate }
2195