4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This is a collection of routines that make up the Card Information
31 * Structure (CIS) interpreter. The algorigthms used are based
32 * on the Release 2.01 PCMCIA standard.
34 * Note that a bunch of comments are not indented correctly with the
35 * code that they are commenting on. This is because cstyle is
36 * inflexible concerning 4-column indenting.
39 #include <sys/types.h>
40 #include <sys/systm.h>
47 #include <sys/autoconf.h>
51 #include <sys/sunddi.h>
52 #include <sys/debug.h>
53 #include <sys/kstat.h>
55 #include <sys/modctl.h>
57 #include <sys/callb.h>
59 #include <sys/pctypes.h>
60 #include <pcmcia/sys/cs_types.h>
61 #include <sys/pcmcia.h>
62 #include <sys/sservice.h>
63 #include <pcmcia/sys/cis.h>
64 #include <pcmcia/sys/cis_handlers.h>
65 #include <pcmcia/sys/cs.h>
66 #include <pcmcia/sys/cs_priv.h>
67 #include <pcmcia/sys/cis_protos.h>
68 #include <pcmcia/sys/cs_stubs.h>
71 * Function declarations
73 void *CISParser(int function
, ...);
74 static int (*cis_card_services
)(int, ...) = NULL
;
76 static int cis_process_longlink(cistpl_callout_t
*, cistpl_t
*,
77 cis_info_t
*, cisparse_t
*);
78 static int cis_create_cis_chain(cs_socket_t
*, cistpl_callout_t
*,
79 cisptr_t
*, cis_info_t
*, cisparse_t
*);
80 static void cis_store_cis_addr(cistpl_t
*, cisptr_t
*);
82 extern cistpl_callout_t cistpl_std_callout
[];
83 extern cistpl_devspeed_struct_t cistpl_devspeed_struct
;
90 * cisp_init - initialize the CIS parser
99 * Fill out the function for CISSetAddress
101 csr
.cs_magic
= PCCS_MAGIC
;
102 csr
.cs_version
= PCCS_VERSION
;
103 csr
.cs_event
= (f_t
*)CISParser
;
106 * We have to call SS instead of CS to register because we
107 * can't do a _depends_on for CS
109 SocketServices(CISSetAddress
, &csr
);
114 * cis_deinit - deinitialize the CIS parser
121 * Tell CS that we're gone.
123 if (cis_card_services
)
124 CIS_CARD_SERVICES(CISUnregister
);
131 * CISParser - this is the entrypoint for all of the CIS Interpreter
135 CISParser(int function
, ...)
138 void *retcode
= (void *)CS_UNSUPPORTED_FUNCTION
;
140 #if defined(CIS_DEBUG)
142 cmn_err(CE_CONT
, "CISParser: called with function 0x%x\n",
147 va_start(arglist
, function
);
150 * ...and here's the CIS Interpreter waterfall
153 case CISP_CIS_SETUP
: {
157 csr
= va_arg(arglist
, csregister_t
*);
158 cis_card_services
= csr
->cs_card_services
;
160 cisr
.cis_magic
= PCCS_MAGIC
;
161 cisr
.cis_version
= PCCS_VERSION
;
162 cisr
.cis_parser
= NULL
; /* let the framework do this */
163 cisr
.cistpl_std_callout
= cistpl_std_callout
;
166 * Tell CS that we're here and what our
167 * entrypoint address is.
169 CIS_CARD_SERVICES(CISRegister
, &cisr
);
170 } /* CISP_CIS_SETUP */
172 case CISP_CIS_LIST_CREATE
: {
173 cistpl_callout_t
*cistpl_callout
;
176 cistpl_callout
= va_arg(arglist
, cistpl_callout_t
*);
177 sp
= va_arg(arglist
, cs_socket_t
*);
180 (uintptr_t)cis_list_create(cistpl_callout
, sp
);
183 case CISP_CIS_LIST_DESTROY
: {
186 sp
= va_arg(arglist
, cs_socket_t
*);
188 retcode
= (void *)(uintptr_t)cis_list_destroy(sp
);
191 case CISP_CIS_GET_LTUPLE
: {
196 tp
= va_arg(arglist
, cistpl_t
*);
197 type
= va_arg(arglist
, uint_t
);
198 flags
= va_arg(arglist
, int);
200 retcode
= (void *)cis_get_ltuple(tp
, type
, flags
);
204 case CISP_CIS_PARSE_TUPLE
: {
205 cistpl_callout_t
*co
;
211 co
= va_arg(arglist
, cistpl_callout_t
*);
212 tp
= va_arg(arglist
, cistpl_t
*);
213 flags
= va_arg(arglist
, int);
214 arg
= va_arg(arglist
, void *);
215 subtype
= va_arg(arglist
, uint_t
);
217 retcode
= (void *)(uintptr_t)cis_tuple_handler(co
, tp
,
218 flags
, arg
, subtype
);
222 case CISP_CIS_CONV_DEVSPEED
:
223 retcode
= (void *)(uintptr_t)cis_convert_devspeed(
224 va_arg(arglist
, convert_speed_t
*));
227 case CISP_CIS_CONV_DEVSIZE
:
228 retcode
= (void *)(uintptr_t)cis_convert_devsize(
229 va_arg(arglist
, convert_size_t
*));
242 * cis_list_lcreate - read a PC card's CIS and create a local linked CIS list
244 * cistpl_callout_t *cistpl_callout - pointer to callout structure
245 * array to use to find tuples.
246 * cisptr_t cisptr - pointer to a structure containing the handle and
247 * offset from where we should start reading
248 * CIS bytes as well as misc flags.
249 * cis_info_t *cis_info - pointer to a cis_info_t structure; pass
250 * the cis_info->cis member as a NULL pointer
251 * if you want to create a new list.
252 * cisparse_t *cisparse - pointer to a cisparse_t struture to put
253 * parsed longlink tuple data into.
254 * cs_socket_t *sp - pointer to a cs_socket_t structure that describes
255 * the socket and card in this socket.
257 * We return the a count of the number of tuples that we saw, not including
258 * any CISTPL_END or CISTPL_NULL tuples if there were no problems
259 * processing the CIS. If a tuple handler returns an error, we
260 * immediately return with the error code from the handler. An
261 * error return code will always have the HANDTPL_ERROR bit set
262 * to allow the caller to distinguish an error from a valid tuple
265 * The nchains and ntuples counters in the cis_info_t structure are also
266 * updated to reflect the number of chains and number of tuples in
269 * XXX need to add CISTPL_END and CISTPL_NULL tuples to the list, and need
270 * to be sure that the tuple count reflects these tuples
272 * If we attempt to read beyond the end of the mapped in CIS address space,
273 * the BAD_CIS_ADDR error code is returned.
275 * This function only interprets the CISTPL_END and CISTPL_NULL tuples as
276 * well as any tuple with a link field of CISTPL_END.
278 * Tuples of type CISTPL_END or CISTPL_NULL are not added to the list.
280 * To append tuples to end of a local linked CIS list, pass a pointer to the
281 * address of the last element in the list that you want tuples appended
282 * to. This pointer should be passed in cis_info->cis.
284 * To process tuple chains with any long link targets, call this routine
285 * for each tuple chain you want to process using the list append method
286 * described above. The caller is responsible for vaildating any link
287 * target tuples to be sure that they describe a valid CIS chain.
289 * The cis_info->flags member is updated as follows:
291 * CW_VALID_CIS - if the CIS is valid
292 * CW_LONGLINK_MFC_FOUND - if a CISTPL_LONGLINK_MFC tuple
294 * CW_LONGLINK_A_FOUND - if a CISTPL_LONGLINK_A tuple was
296 * CW_LONGLINK_C_FOUND - if a CISTPL_LONGLINK_C tuple was
299 * If a CISTPL_LONGLINK_MFC, CISTPL_LONGLINK_A or CISTPL_LONGLINK_C
300 * tuple is seen, the *cisparse argument will return an appropriate
301 * parsed longlink structure as follows:
303 * CW_LONGLINK_MFC_FOUND:
304 * *cisparse --> cistpl_longlink_mfc_t *
305 * CW_LONGLINK_A_FOUND, CW_LONGLINK_C_FOUND:
306 * *cisparse --> cistpl_longlink_ac_t *
308 * These flags are set and the tuples are parsed so that the caller does
309 * not have to traverse the CIS list to find out if any of these tuples
312 * For each tuple that we see, the following flags in the tuple_t->flags member
315 * CISTPLF_COPYOK - OK to copy tuple data
316 * CISTPLF_GLOBAL_CIS - tuple from global CIS
317 * CISTPLF_MF_CIS - tuple from MF CIS chain
318 * CISTPLF_FROM_AM - tuple read from AM space
319 * CISTPLF_FROM_CM - tuple read from CM space
320 * CISTPLF_LINK_INVALID - tuple link is invalid
321 * CISTPLF_PARAMS_INVALID - tuple body is invalid
322 * CISTPLF_AM_SPACE - this tuple is in AM space
323 * CISTPLF_CM_SPACE - this tuple is in CM space
324 * CISTPLF_LM_SPACE - this tuple is in local memory
327 cis_list_lcreate(cistpl_callout_t
*cistpl_callout
, cisptr_t
*cisptr
,
328 cis_info_t
*cis_info
, cisparse_t
*cisparse
, cs_socket_t
*sp
)
330 cistpl_t
*cp
, *tp
= NULL
;
331 cisdata_t tl
, td
, *dp
;
333 get_socket_t get_socket
;
337 * If we were passed a non-NULL list base, that means that we should
338 * parse the CIS and add any tuples we find to the end of the list
339 * we were handed a pointer to.
345 get_socket
.socket
= sp
->socket_num
;
346 if (SocketServices(SS_GetSocket
, &get_socket
) != SUCCESS
) {
348 "cis_list_lcreate: socket %d SS_GetSocket failed\n",
350 return (CS_BAD_SOCKET
);
354 * If this is primary CIS chain, the first tuple must be one
355 * from the following list.
356 * Ref. PC Card 95, Metaformat Specification, Page 7.
357 * XXX Need to think this out a bit more to deal with 3.3V
358 * cards and the description of where a CISTPL_DEVICE
362 #if defined(CIS_DEBUG)
364 cmn_err(CE_CONT
, "cis_list_lcreate: td=0x%x cisptr=%p\n",
365 GET_CIS_DATA(cisptr
), (void *)cisptr
);
366 cmn_err(CE_CONT
, "\t flags=0x%x CW_CHECK_PRIMARY_CHAIN=0x%x\n",
367 cis_info
->flags
, CW_CHECK_PRIMARY_CHAIN
);
368 cmn_err(CE_CONT
, "\t IFType=0x%x IF_MEMORY=0x%x\n",
369 get_socket
.IFType
, IF_MEMORY
);
373 if (cis_info
->flags
& CW_CHECK_PRIMARY_CHAIN
) {
374 switch (td
= GET_CIS_DATA(cisptr
)) {
377 case CISTPL_LINKTARGET
:
381 * Magicram memory cards without attribute memory
382 * do not have a CIS and return CISTPL_NULL.
384 if (get_socket
.IFType
== IF_MEMORY
)
391 } /* CW_CHECK_PRIMARY_CHAIN */
394 * Update the number of chains counter
399 * The main tuple processing loop. We'll exit this loop when either
400 * a tuple's link field is CISTPL_END or we've seen a tuple type
401 * field of CISTPL_END.
403 * Note that we also silently throw away CISTPL_NULL tuples, and don't
404 * include them in the tuple count that we return.
406 while (!done
&& ((td
= GET_CIS_DATA(cisptr
)) !=
407 (cisdata_t
)CISTPL_END
)) {
409 #if defined(CIS_DEBUG)
410 if ((cis_debug
> 1) && (td
!= 0)) {
411 cmn_err(CE_CONT
, "cis_list_lcreate: td=0x%x cisptr=%p"
413 td
, (void *)cisptr
, cisptr
->offset
);
418 * Ignore CISTPL_NULL tuples
420 if (td
!= (cisdata_t
)CISTPL_NULL
) {
422 * point to tuple link field and get the link value
424 if (!NEXT_CIS_ADDR(cisptr
))
425 return ((uint32_t)BAD_CIS_ADDR
);
426 tl
= GET_CIS_DATA(cisptr
);
428 * This is an ugly PCMCIA hack - ugh! since the standard allows
429 * a link byte of CISTPL_END to signify that this is the
430 * last tuple. The problem is that this tuple might
431 * actually contain useful information, but we don't know
433 * We do know that it can't be more than CIS_MAX_TUPLE_DATA_LEN
434 * bytes in length, however. So, we pretend that the link
435 * byte is CIS_MAX_TUPLE_DATA_LEN and also set a flag so
436 * that when we're done processing this tuple, we will
437 * break out of the while loop.
439 if (tl
== (cisdata_t
)CISTPL_END
) {
440 tl
= CIS_MAX_TUPLE_DATA_LEN
;
445 * point to first byte of tuple data, allocate a new list
446 * element and diddle with the list base and list
449 if (!NEXT_CIS_ADDR(cisptr
))
450 return ((uint32_t)BAD_CIS_ADDR
);
451 cp
= (cistpl_t
*)CIS_MEM_ALLOC(sizeof (cistpl_t
));
454 * if we're not the first in the list, point to our
460 * will be NULL if we're the first element of the
466 * if this is the first element, save it's address
474 * Save the address in CIS space that this tuple
475 * begins at, as well as set tuple flags.
477 cis_store_cis_addr(tp
, cisptr
);
480 * If this tuple has tuple data, we might need to
482 * Note that the tuple data pointer (tp->data) will
483 * be set to NULL for a tuple with no data.
489 * Read the data in the tuple and store it
490 * away locally if we're allowed to. If
491 * the CISTPLF_COPYOK flag is set, it means
492 * that it's OK to touch the data portion
495 * We need to make this check since some
496 * tuples might contain active registers
497 * that can alter the device state if they
498 * are read before the card is correctly
499 * initialized. What a stupid thing to
500 * allow in a standard, BTW.
502 * We first give the tuple handler a chance
503 * to set any tuple flags that it wants
504 * to, then we (optionally) do the data
505 * copy, and give the tuple handler another
508 * ref. PC Card Standard Release 2.01 in the
509 * Card Metaformat section, section 5.2.6,
512 if ((err
= cis_tuple_handler(cistpl_callout
, tp
,
513 HANDTPL_SET_FLAGS
, NULL
, 0)) &
517 if (tl
> (unsigned)0) {
520 * if we're supposed to make a local copy of
521 * the tuple data, allocate space for it,
522 * otherwise just record the PC card
523 * starting address of this tuple.
524 * The address was saved by cis_store_cis_addr.
526 if (tp
->flags
& CISTPLF_COPYOK
) {
527 tp
->data
= (cisdata_t
*)CIS_MEM_ALLOC(tl
);
530 tp
->data
= GET_CIS_ADDR(tp
);
534 if (tp
->flags
& CISTPLF_COPYOK
)
535 *dp
++ = GET_CIS_DATA(cisptr
);
536 if (!NEXT_CIS_ADDR(cisptr
))
537 return ((uint32_t)BAD_CIS_ADDR
);
541 * If we made a local copy of the tuple data,
542 * then clear the AM and CM flags; if the
543 * tuple data is still on the card, then
544 * leave the flags alone.
546 if (tp
->flags
& CISTPLF_COPYOK
) {
547 tp
->flags
&= ~CISTPLF_SPACE_MASK
;
548 tp
->flags
|= CISTPLF_LM_SPACE
;
552 * This is a tuple with no data in it's body, so
553 * we just set the data pointer to NULL.
559 * tp->flags &= ~(CISTPLF_SPACE_MASK |
560 * CISTPLF_FROM_MASK);
566 * The main idea behind this call is to give
567 * the handler a chance to validate the
570 if ((err
= cis_tuple_handler(cistpl_callout
, tp
,
571 HANDTPL_COPY_DONE
, NULL
, 0)) &
576 } else { /* if (tl) */
582 * Check to see if this is a longlink tuple and if
583 * so, do the necessary processing.
585 if ((err
= cis_process_longlink(cistpl_callout
, tp
,
592 } else { /* if (td == CISTPL_NULL) */
594 * If we're a CISTPL_NULL we need to skip to
595 * the beginning of the next tuple.
597 if (!NEXT_CIS_ADDR(cisptr
))
598 return ((uint32_t)BAD_CIS_ADDR
);
600 } /* while (!done && !CISTPL_END) */
602 #if defined(CIS_DEBUG)
604 cmn_err(CE_CONT
, "cis_list_lcreate: exit nchains=%x ntuples=%x\n",
605 cis_info
->nchains
, cis_info
->ntuples
);
609 return (cis_info
->ntuples
);
613 * cis_process_longlink - processes longlink tuples
615 * This function examines the passed-in tuple type and if it is a
616 * longlink tuple, the tuple is parsed and the appropriate flags in
617 * cis_info->flags are set.
619 * If there is an error parsing the tuple, HANDTPL_ERROR is returned
620 * and the CW_LONGLINK_FOUND flags in cis_info->flags are cleared.
623 cis_process_longlink(cistpl_callout_t
*cistpl_callout
, cistpl_t
*tp
,
624 cis_info_t
*cis_info
, cisparse_t
*cisparse
)
627 * If this is a CISTPL_LONGLINK_A, CISTPL_LONGLINK_C
628 * or CISTPL_LONGLINK_MFC tuple, parse the tuple
629 * and set appropriate CW_LONGLINK_XXX_FOUND flags.
630 * If this is a CISTPL_NO_LINK tuple, or if there is an
631 * error parsing the tuple, clear all the
632 * CW_LONGLINK_XXX_FOUND flags.
635 case CISTPL_LONGLINK_A
:
636 case CISTPL_LONGLINK_C
:
637 case CISTPL_LONGLINK_MFC
:
638 cis_info
->flags
&= ~CW_LONGLINK_FOUND
;
639 if (cis_tuple_handler(cistpl_callout
, tp
,
640 HANDTPL_PARSE_LTUPLE
,
643 return (HANDTPL_ERROR
);
645 case CISTPL_LONGLINK_A
:
646 cis_info
->flags
|= CW_LONGLINK_A_FOUND
;
648 case CISTPL_LONGLINK_C
:
649 cis_info
->flags
|= CW_LONGLINK_C_FOUND
;
651 case CISTPL_LONGLINK_MFC
:
652 cis_info
->flags
|= CW_LONGLINK_MFC_FOUND
;
654 } /* switch (tp->type) */
657 cis_info
->flags
&= ~CW_LONGLINK_FOUND
;
659 } /* switch (tp->type) */
661 return (HANDTPL_NOERROR
);
665 * cis_list_ldestroy - function to destroy a linked tuple list
667 * cistpl_t *cistplbase - pointer to a pointer to the base of a
668 * local linked CIS list to destroy; the
669 * data that this pointer points to is
672 * Once this function returns, cistplbase is set to NULL.
675 cis_list_ldestroy(cistpl_t
**cistplbase
)
681 * First, check to see if we've got a
682 * non-NULL list pointer.
684 if ((tp
= *cistplbase
) == NULL
)
689 * Free any data that may be allocated
691 if ((tp
->flags
& CISTPLF_COPYOK
) &&
692 (tp
->flags
& CISTPLF_LM_SPACE
) &&
694 CIS_MEM_FREE((caddr_t
)tp
->data
);
701 CIS_MEM_FREE((caddr_t
)tp
);
709 * Now clear the pointer to the non-existant
719 * cis_get_ltuple - function to walk local linked CIS list and return
720 * a tuple based on various criteria
722 * cistpl_t *tp - pointer to any valid tuple in the list
723 * cisdata_t type - type of tuple to search for
724 * int flags - type of action to perform (each is mutually exclusive)
725 * GET_FIRST_LTUPLEF, GET_LAST_LTUPLEF:
726 * Returns the {first|last} tuple in the list.
727 * FIND_LTUPLE_FWDF, FIND_LTUPLE_BACKF:
728 * FIND_NEXT_LTUPLEF, FIND_PREV_LTUPLEF:
729 * Returns the first tuple that matches the passed tuple type,
730 * searching the list {forward|backward}.
731 * GET_NEXT_LTUPLEF, GET_PREV_LTUPLEF:
732 * Returns the {next|previous} tuple in the list.
734 * The following bits can be set in the flags parameter:
735 * CIS_GET_LTUPLE_IGNORE - return tuples with
736 * CISTPLF_IGNORE_TUPLE set in cistpl_t->flags
739 * When using the FIND_LTUPLE_FWDF and FIND_LTUPLE_BACKF flags,
740 * the search starts at the passed tuple. Continually calling this
741 * function with a tuple that is the same type as the passed type will
742 * continually return the same tuple.
744 * When using the FIND_NEXT_LTUPLEF and FIND_PREV_LTUPLEF flags,
745 * the search starts at the {next|previous} tuple from the passed tuple.
748 * cistpl_t * - pointer to tuple in list
749 * NULL - if error while processing list or tuple not found
751 #define GET_NEXT_LTUPLE(tp) ((tp->next)?tp->next:NULL)
752 #define GET_PREV_LTUPLE(tp) ((tp->prev)?tp->prev:NULL)
754 cis_get_ltuple(cistpl_t
*tp
, cisdata_t type
, uint32_t flags
)
756 cistpl_t
*ltp
= NULL
;
761 switch (flags
& CIS_GET_LTUPLE_OPMASK
) {
762 case GET_FIRST_LTUPLEF
: /* return first tuple in list */
765 } while ((tp
= GET_PREV_LTUPLE(tp
)) != NULL
);
767 if (!(flags
& CIS_GET_LTUPLE_IGNORE
))
768 while (ltp
&& (ltp
->flags
& CISTPLF_IGNORE_TUPLE
))
769 ltp
= GET_NEXT_LTUPLE(ltp
);
771 case GET_LAST_LTUPLEF
: /* return last tuple in list */
774 } while ((tp
= GET_NEXT_LTUPLE(tp
)) != NULL
);
776 if (!(flags
& CIS_GET_LTUPLE_IGNORE
))
777 while (ltp
&& (ltp
->flags
& CISTPLF_IGNORE_TUPLE
))
778 ltp
= GET_PREV_LTUPLE(ltp
);
780 case FIND_LTUPLE_FWDF
: /* find tuple, fwd search from tp */
782 if (tp
->type
== type
)
783 if ((flags
& CIS_GET_LTUPLE_IGNORE
) ||
784 (!(tp
->flags
& CISTPLF_IGNORE_TUPLE
)))
785 return (tp
); /* note return here */
786 } while ((tp
= GET_NEXT_LTUPLE(tp
)) != NULL
);
788 case FIND_LTUPLE_BACKF
:
789 /* find tuple, backward search from tp */
791 if (tp
->type
== type
)
792 if ((flags
& CIS_GET_LTUPLE_IGNORE
) ||
793 (!(tp
->flags
& CISTPLF_IGNORE_TUPLE
)))
794 return (tp
); /* note return here */
795 } while ((tp
= GET_PREV_LTUPLE(tp
)) != NULL
);
797 case FIND_NEXT_LTUPLEF
: /* find tuple, fwd search from tp+1 */
798 while ((tp
= GET_NEXT_LTUPLE(tp
)) != NULL
) {
799 if (tp
->type
== type
)
800 if ((flags
& CIS_GET_LTUPLE_IGNORE
) ||
801 (!(tp
->flags
& CISTPLF_IGNORE_TUPLE
)))
802 return (tp
); /* note return here */
805 case FIND_PREV_LTUPLEF
:
806 /* find tuple, backward search from tp-1 */
807 while ((tp
= GET_PREV_LTUPLE(tp
)) != NULL
) {
808 if (tp
->type
== type
)
809 if ((flags
& CIS_GET_LTUPLE_IGNORE
) ||
810 (!(tp
->flags
& CISTPLF_IGNORE_TUPLE
)))
811 return (tp
); /* note return here */
814 case GET_NEXT_LTUPLEF
: /* return next tuple in list */
816 while (((ltp
= GET_NEXT_LTUPLE(ltp
)) != NULL
) &&
817 (!(flags
& CIS_GET_LTUPLE_IGNORE
)) &&
818 (ltp
->flags
& CISTPLF_IGNORE_TUPLE
))
821 case GET_PREV_LTUPLEF
: /* return prev tuple in list */
823 while (((ltp
= GET_PREV_LTUPLE(ltp
)) != NULL
) &&
824 (!(flags
& CIS_GET_LTUPLE_IGNORE
)) &&
825 (ltp
->flags
& CISTPLF_IGNORE_TUPLE
))
828 default: /* ltp is already NULL in the initialization */
836 * cis_convert_devspeed - converts a devspeed value to nS or nS
837 * to a devspeed entry
840 cis_convert_devspeed(convert_speed_t
*cs
)
842 cistpl_devspeed_struct_t
*cd
= &cistpl_devspeed_struct
;
843 unsigned exponent
= 0, mantissa
= 0;
846 * Convert nS to a devspeed value
848 if (cs
->Attributes
& CONVERT_NS_TO_DEVSPEED
) {
849 unsigned tnS
, tmanv
= 0, i
;
852 * There is no device speed code for 0nS
855 return (CS_BAD_SPEED
);
858 * Handle any nS value below 10nS specially since the code
859 * below only works for nS values >= 10. Now, why anyone
860 * would want to specify a nS value less than 10 is
861 * certainly questionable, but it is allowed by the spec.
865 mantissa
= CISTPL_DEVSPEED_MAX_MAN
;
868 /* find the exponent */
869 for (i
= 0; i
< CISTPL_DEVSPEED_MAX_EXP
; i
++) {
870 if ((!(tnS
= ((cs
->nS
)/10))) ||
871 (mantissa
== CISTPL_DEVSPEED_MAX_MAN
)) {
872 /* find the mantissa */
873 for (mantissa
= 0; mantissa
< CISTPL_DEVSPEED_MAX_MAN
;
875 if (cd
->mantissa
[mantissa
] == tmanv
) {
876 cs
->devspeed
= ((((mantissa
<<3) |
877 (exponent
& (CISTPL_DEVSPEED_MAX_EXP
- 1)))));
880 } /* for (mantissa<CISTPL_DEVSPEED_MAX_MAN) */
886 } /* for (i<CISTPL_DEVSPEED_MAX_EXP) */
888 * Convert a devspeed value to nS
890 } else if (cs
->Attributes
& CONVERT_DEVSPEED_TO_NS
) {
891 exponent
= (cs
->devspeed
& (CISTPL_DEVSPEED_MAX_TBL
- 1));
892 if ((mantissa
= (((cs
->devspeed
)>>3) &
893 (CISTPL_DEVSPEED_MAX_MAN
- 1))) == NULL
) {
894 if ((cs
->nS
= cd
->table
[exponent
]) == NULL
)
895 return (CS_BAD_SPEED
);
898 if ((cs
->nS
= ((cd
->mantissa
[mantissa
] *
899 cd
->exponent
[exponent
]) / 10)) == NULL
)
900 return (CS_BAD_SPEED
);
904 return (CS_BAD_ATTRIBUTE
);
907 return (CS_BAD_SPEED
);
911 * This array is for the cis_convert_devsize function.
913 static uint32_t cistpl_device_size
[8] =
914 { 512, 2*1024, 8*1024, 32*1024, 128*1024, 512*1024, 2*1024*1024, 0 };
917 * cis_convert_devsize - converts a devsize value to a size in bytes value
918 * or a size in bytes value to a devsize value
921 cis_convert_devsize(convert_size_t
*cs
)
925 if (cs
->Attributes
& CONVERT_BYTES_TO_DEVSIZE
) {
926 if ((cs
->bytes
< cistpl_device_size
[0]) ||
927 (cs
->bytes
> (cistpl_device_size
[6] * 32)))
928 return (CS_BAD_SIZE
);
930 for (i
= 6; i
>= 0; i
--)
931 if (cs
->bytes
>= cistpl_device_size
[i
])
934 cs
->devsize
= ((((cs
->bytes
/cistpl_device_size
[i
]) - 1) << 3) |
937 } else if (cs
->Attributes
& CONVERT_DEVSIZE_TO_BYTES
) {
938 if ((cs
->devsize
& 7) == 7)
939 return (CS_BAD_SIZE
);
941 cistpl_device_size
[cs
->devsize
& 7] * ((cs
->devsize
>> 3) + 1);
943 return (CS_BAD_ATTRIBUTE
);
950 * cis_list_create - reads the card's CIS and creates local CIS lists for
951 * each function on the card
953 * This function will read the CIS on the card, follow all CISTPL_LONGLINK_A,
954 * CISTPL_LONGLINK_C and CISTPL_LONGLINK_MFC tuples and create local CIS
955 * lists for each major CIS chain on the card.
957 * If there are no errors, the parameters returned are:
958 * For a non-multifunction card:
959 * sp->cis_flags - CW_VALID_CIS set
960 * sp->nfuncs - set to 0x0
961 * sp->cis[CS_GLOBAL_CIS] - contains CIS list
962 * sp->cis[CS_GLOBAL_CIS].cis_flags - CW_VALID_CIS set
964 * For a multifunction card:
966 * sp->cis_flags - CW_VALID_CIS & CW_MULTI_FUNCTION_CIS set
967 * sp->nfuncs - set to number of functions specified in
968 * the CISTPL_LONGLINK_MFC tuple
969 * sp->cis[CS_GLOBAL_CIS] - contains global CIS list
970 * sp->cis[CS_GLOBAL_CIS].cis_flags - CW_VALID_CIS set
971 * Function-specific CIS values:
972 * sp->cis[0..sp->nfuncs-1] - contains function-specific CIS lists
973 * sp->cis[0..sp->nfuncs-1].cis_flags - CW_VALID_CIS &
974 * CW_MULTI_FUNCTION_CIS set
977 * CS_SUCCESS - if no errors
978 * CS_NO_CIS - if no CIS on card
979 * CS_BAD_WINDOW or CS_GENERAL_FAILURE - if CIS window could
981 * CS_BAD_CIS - if error creating CIS chains
982 * CS_BAD_OFFSET - if cis_list_lcreate tried to read past the
983 * boundries of the allocated CIS window
985 extern cistpl_ignore_list_t cistpl_ignore_list
[];
987 cis_list_create(cistpl_callout_t
*cistpl_callout
, cs_socket_t
*sp
)
991 cis_info_t
*cis_info
;
992 cistpl_longlink_ac_t
*cistpl_longlink_ac
;
993 cistpl_longlink_mfc_t cistpl_longlink_mfc
, *mfc
;
994 cistpl_ignore_list_t
*cil
;
998 * Initialize the CIS structures
1000 bzero((caddr_t
)&sp
->cis
, ((sizeof (cis_info_t
)) * CS_MAX_CIS
));
1003 * Start reading the primary CIS chain at offset 0x0 of AM. Assume
1004 * that there is a CISTPL_LONGLINK_C tuple that points to
1005 * offset 0x0 of CM space.
1006 * Since this is the primary CIS chain, set CW_CHECK_PRIMARY_CHAIN
1007 * so that we'll check for a valid first tuple.
1009 cis_info
= &sp
->cis
[CS_GLOBAL_CIS
];
1010 cis_info
->flags
= (CW_LONGLINK_C_FOUND
| CW_CHECK_PRIMARY_CHAIN
);
1011 cisptr
.flags
= (CISTPLF_AM_SPACE
| CISTPLF_GLOBAL_CIS
);
1012 cisptr
.size
= sp
->cis_win_size
- 1;
1014 cistpl_longlink_ac
= (cistpl_longlink_ac_t
*)&cisparse
;
1015 cistpl_longlink_ac
->flags
= CISTPL_LONGLINK_AC_CM
;
1016 cistpl_longlink_ac
->tpll_addr
= 0;
1018 if ((ret
= cis_create_cis_chain(sp
, cistpl_callout
, &cisptr
,
1019 cis_info
, &cisparse
)) !=
1022 } /* cis_create_cis_chain */
1025 * If there are no tuples in the primary CIS chain, it means that
1026 * this card doesn't have a CIS on it.
1028 if (cis_info
->ntuples
== 0)
1032 * Mark this CIS list as being valid.
1034 cis_info
->flags
|= CW_VALID_CIS
;
1037 * Mark this socket as having at least one valid CIS chain.
1039 sp
->cis_flags
|= CW_VALID_CIS
;
1043 * If the primary CIS chain specified that there are function-specific
1044 * CIS chains, we need to create each of these chains. If not,
1045 * then we're all done and we can return.
1047 if (!(cis_info
->flags
& CW_LONGLINK_MFC_FOUND
))
1048 return (CS_SUCCESS
);
1051 * Mark this socket as having a multi-function CIS.
1053 sp
->cis_flags
|= CW_MULTI_FUNCTION_CIS
;
1056 * At this point, cis_create_cis_chain has told us that the primary
1057 * CIS chain says that there are function-specific CIS chains
1058 * on the card that we need to follow. The cisparse variable now
1059 * contains the parsed output of the CISTPL_LONGLINK_MFC
1060 * tuple. We need to save that information and then process
1061 * each function-specific CIS chain.
1063 bcopy((caddr_t
)&cisparse
, (caddr_t
)&cistpl_longlink_mfc
,
1064 sizeof (cistpl_longlink_mfc_t
));
1065 mfc
= &cistpl_longlink_mfc
;
1066 sp
->nfuncs
= mfc
->nregs
;
1069 * Go through and create a CIS list for each function-specific
1070 * CIS chain on the card. Set CW_CHECK_LINKTARGET since all
1071 * function-specific CIS chains must begin with a valid
1072 * CISTPL_LINKTARGET tuple. Also set CW_RET_ON_LINKTARGET_ERROR
1073 * since we want to return an error if the CISTPL_LINKTARGET
1074 * tuple is invalid or missing.
1076 for (fn
= 0; fn
< sp
->nfuncs
; fn
++) {
1077 cis_info
= &sp
->cis
[fn
];
1078 cis_info
->flags
= (CW_CHECK_LINKTARGET
|
1079 CW_RET_ON_LINKTARGET_ERROR
);
1081 * If the function-specific CIS chain starts
1082 * in AM space, then multiply address by
1083 * 2 since only even bytes are counted in
1084 * the CIS when AM addresses are specified,
1086 * address as specified.
1088 if (mfc
->function
[fn
].tas
== CISTPL_LONGLINK_MFC_TAS_AM
) {
1089 cisptr
.flags
= (CISTPLF_AM_SPACE
| CISTPLF_MF_CIS
);
1090 cisptr
.offset
= mfc
->function
[fn
].addr
* 2;
1092 cisptr
.flags
= (CISTPLF_CM_SPACE
| CISTPLF_MF_CIS
);
1093 cisptr
.offset
= mfc
->function
[fn
].addr
;
1096 if ((ret
= cis_create_cis_chain(sp
, cistpl_callout
, &cisptr
,
1097 cis_info
, &cisparse
)) !=
1100 "cis_list_create: socket %d ERROR_MFC = 0x%x\n",
1101 sp
->socket_num
, ret
);
1103 } /* cis_create_cis_chain */
1106 * Mark this CIS list as being valid and as being a
1107 * function-specific CIS list.
1109 cis_info
->flags
|= (CW_VALID_CIS
| CW_MULTI_FUNCTION_CIS
);
1112 * Check for tuples that we want to ignore
1113 * in the global CIS. If the tuple exists
1114 * in the global CIS and in at least one
1115 * of the function-specific CIS lists, then
1117 * in the global CIS to be ignored.
1119 cil
= &cistpl_ignore_list
[0];
1120 while (cil
->type
!= CISTPL_NULL
) {
1121 if (cis_get_ltuple(sp
->cis
[fn
].cis
, cil
->type
,
1123 CIS_GET_LTUPLE_IGNORE
) != NULL
) {
1124 cistpl_t
*gtp
= sp
->cis
[CS_GLOBAL_CIS
].cis
;
1125 while ((gtp
= cis_get_ltuple(gtp
, cil
->type
,
1127 CIS_GET_LTUPLE_IGNORE
)) != NULL
) {
1128 gtp
->flags
|= CISTPLF_IGNORE_TUPLE
;
1129 gtp
= cis_get_ltuple(gtp
, NULL
, GET_NEXT_LTUPLEF
|
1130 CIS_GET_LTUPLE_IGNORE
);
1132 } /* if (cis_get_ltuple(cis[fn])) */
1137 return (CS_SUCCESS
);
1141 * cis_create_cis_chain - creates a single CIS chain
1143 * This function reads the CIS on a card and follows any CISTPL_LONGLINK_A
1144 * and CISTPL_LONGLINK_C link tuples to create a single CIS chain. We
1145 * keep reading the CIS and following any CISTPL_LONGLINK_A and
1146 * CISTPL_LONGLINK_C tuples until we don't see anymore. If we see a
1147 * CISTPL_LONGLINK_MFC tuple, we return - the caller is responsible
1148 * for following CIS chains on a per-function level.
1150 * The following parameters must be initialized by the caller:
1152 * sp - pointer to a cs_socket_t structure that describes the socket
1153 * and card in this socket
1154 * cistpl_callout - pointer to a cistpl_callout_t array of structures
1155 * cisptr->flags - either CISTPLF_AM_SPACE or CISTPLF_CM_SPACE
1156 * cisptr->size - size of CIS window
1157 * cisptr->offset - offset in AM or CM space on card to start
1158 * reading tuples from
1159 * cis_info - pointer to a cis_info_t structure where this list will
1161 * cisparse - pointer to a cisparse_t structure where the last longlink
1162 * parsed tuple data will be returned
1164 * To check the CISTPL_LINKTARGET tuple at the beginning of the first
1165 * CIS chain that this function encounters, set CW_CHECK_LINKTARGET
1166 * in cis_info->flags before calling this function.
1168 * This function returns:
1170 * CS_SUCCESS - if CIS chain was created sucessfully or there
1171 * were no tuples found on the first CIS chain
1172 * CS_BAD_WINDOW or CS_GENERAL_FAILURE - if CIS window could
1174 * CS_BAD_CIS - if error creating CIS chain
1175 * CS_BAD_OFFSET - if cis_list_lcreate tried to read past the
1176 * boundries of the allocated CIS window
1178 * Note that if the first tuple of the target CIS chain is supposed
1179 * to contain a CISTPL_LINKTARGET and the target chain does not
1180 * contain that tuple (or that tuple is invalid in some way) and
1181 * the CW_RET_ON_LINKTARGET_ERROR flag is not set, we don't flag
1182 * this as an error, we just return. This is to handle the case
1183 * where the target chain is in uninitialized memory and will be
1184 * initialized later.
1185 * To return an error if an invalid CISTPL_LINKTARGET tuple is seen,
1186 * set the CW_RET_ON_LINKTARGET_ERROR flag in cis_info->flags
1187 * before calling this function.
1190 cis_create_cis_chain(cs_socket_t
*sp
, cistpl_callout_t
*cistpl_callout
,
1191 cisptr_t
*cisptr
, cis_info_t
*cis_info
,
1192 cisparse_t
*cisparse
)
1194 cistpl_t
*tps
= NULL
;
1198 if ((ret
= CIS_CARD_SERVICES(InitCISWindow
, sp
, &cisptr
->offset
,
1199 &cisptr
->handle
, cisptr
->flags
)) != CS_SUCCESS
)
1203 * If we're pointing at a CIS chain that
1204 * is the target of a longlink tuple,
1205 * we need to validate the target chain
1206 * before we try to process it. If the
1207 * CISTPL_LINKTARGET tuple is invalid,
1208 * and the CW_RET_ON_LINKTARGET_ERROR
1209 * is not set, don't flag it as an error,
1212 if (cis_info
->flags
& CW_CHECK_LINKTARGET
) {
1213 cis_info
->flags
&= ~CW_CHECK_LINKTARGET
;
1214 if (cis_validate_longlink_acm(cisptr
) != CISTPLF_NOERROR
) {
1216 cis_info
->cis
= tps
;
1217 if (cis_info
->flags
& CW_RET_ON_LINKTARGET_ERROR
) {
1218 cis_info
->flags
&= ~CW_RET_ON_LINKTARGET_ERROR
;
1219 return (CS_BAD_CIS
);
1221 return (CS_SUCCESS
);
1222 } /* CW_RET_ON_LINKTARGET_ERROR */
1223 } /* cis_validate_longlink_acm */
1224 } /* CW_CHECK_LINKTARGET */
1226 ret
= cis_list_lcreate(cistpl_callout
, cisptr
, cis_info
, cisparse
,
1229 #if defined(CIS_DEBUG)
1230 if (cis_debug
> 1) {
1231 cmn_err(CE_CONT
, "cis_create_cis_chain: ret=0x%x"
1232 " BAD_CIS_ADDR=0x%x CS_BAD_SOCKET=0x%x\n",
1233 ret
, BAD_CIS_ADDR
, CS_BAD_SOCKET
);
1238 if ((ret
& HANDTPL_ERROR
) || (ret
== (uint32_t)BAD_CIS_ADDR
)) {
1240 cis_info
->cis
= tps
;
1241 if (ret
== (uint32_t)BAD_CIS_ADDR
)
1242 return (CS_BAD_OFFSET
);
1244 return (CS_BAD_CIS
);
1248 * If we're creating the primary CIS chain
1249 * and we haven't seen any tuples,
1250 * then return CS_SUCCESS. The caller will
1251 * have to check cis_info->ntuples to find
1252 * out if any tuples were found.
1253 * If we're processing the target of a longlink
1254 * tuple, then by now we have already validated
1255 * the CISTPL_LINKTARGET tuple so that we
1256 * know we'll have at least one tuple in
1259 if (cis_info
->ntuples
== 0)
1260 return (CS_SUCCESS
);
1263 * If we've just created a new list, we need to
1264 * save the pointer to the start of the list.
1267 tps
= cis_info
->cis
;
1269 switch (cis_info
->flags
& CW_LONGLINK_FOUND
) {
1270 cistpl_longlink_ac_t
*cistpl_longlink_ac
;
1272 case CW_LONGLINK_A_FOUND
:
1273 cistpl_longlink_ac
= (cistpl_longlink_ac_t
*)cisparse
;
1274 cisptr
->flags
&= ~(CISTPLF_SPACE_MASK
| CISTPLF_FROM_MASK
);
1275 cisptr
->flags
|= CISTPLF_AM_SPACE
;
1277 * Multiply address by 2 since only
1278 * even bytes are counted in the CIS
1279 * when AM addresses are specified.
1281 cisptr
->offset
= cistpl_longlink_ac
->tpll_addr
* 2;
1282 cis_info
->flags
|= CW_CHECK_LINKTARGET
;
1285 * Point to the last tuple in the list.
1287 cis_info
->cis
= cis_get_ltuple(cis_info
->cis
, NULL
,
1290 case CW_LONGLINK_C_FOUND
:
1291 cistpl_longlink_ac
= (cistpl_longlink_ac_t
*)cisparse
;
1292 cisptr
->flags
&= ~(CISTPLF_SPACE_MASK
| CISTPLF_FROM_MASK
);
1293 cisptr
->flags
|= CISTPLF_CM_SPACE
;
1294 cisptr
->offset
= cistpl_longlink_ac
->tpll_addr
;
1295 cis_info
->flags
|= CW_CHECK_LINKTARGET
;
1298 * Point to the last tuple in the list.
1300 cis_info
->cis
= cis_get_ltuple(cis_info
->cis
, NULL
,
1303 case CW_LONGLINK_MFC_FOUND
:
1307 } /* switch (cis_info->flags) */
1309 } while (cis_info
->flags
& (CW_LONGLINK_A_FOUND
| CW_LONGLINK_C_FOUND
));
1312 * If we needed to save a pointer to the start of the list because
1313 * we saw a longlink tuple, restore the list head pointer now.
1316 cis_info
->cis
= tps
;
1318 return (CS_SUCCESS
);
1322 * cis_list_destroy - destroys the local CIS list
1325 cis_list_destroy(cs_socket_t
*sp
)
1330 * Destroy any CIS list that we may have created. It's OK to pass
1331 * a non-existant CIS list pointer to cis_list_ldestroy since
1332 * that function will not do anything if there is nothing in
1333 * the passed CIS list to cleanup.
1335 for (fn
= 0; fn
< CS_MAX_CIS
; fn
++)
1336 (void) cis_list_ldestroy(&sp
->cis
[fn
].cis
);
1339 * Clear out any remaining state.
1341 bzero((caddr_t
)&sp
->cis
, ((sizeof (cis_info_t
)) * CS_MAX_CIS
));
1345 return (CS_SUCCESS
);
1349 * cis_store_cis_addr - saves the current CIS address and space type
1350 * of the beginning of the tuple into the passed linked list element.
1351 * Note that this function will decrement the CIS address by two
1352 * elements prior to storing it to the linked list element to point
1353 * to the tuple type byte.
1355 * This function also sets the following flags in tp->flags if they are set
1358 * CISTPLF_GLOBAL_CIS - tuple in global CIS
1359 * CISTPLF_MF_CIS - tuple in function-specific CIS
1362 cis_store_cis_addr(cistpl_t
*tp
, cisptr_t
*ptr
)
1365 if (ptr
->flags
& CISTPLF_AM_SPACE
)
1366 tp
->offset
= ptr
->offset
- 4;
1368 tp
->offset
= ptr
->offset
- 2;
1370 tp
->flags
&= ~(CISTPLF_SPACE_MASK
| CISTPLF_FROM_MASK
|
1371 CISTPLF_GLOBAL_CIS
| CISTPLF_MF_CIS
);
1372 tp
->flags
|= (ptr
->flags
& (CISTPLF_SPACE_MASK
|
1373 CISTPLF_GLOBAL_CIS
| CISTPLF_MF_CIS
));
1375 if (tp
->flags
& CISTPLF_AM_SPACE
)
1376 tp
->flags
|= CISTPLF_FROM_AM
;
1378 if (tp
->flags
& CISTPLF_CM_SPACE
)
1379 tp
->flags
|= CISTPLF_FROM_CM
;