Import 2.3.32pre1
[davej-history.git] / drivers / pcmcia / cistpl.c
blobc2cd8e7855139d62936bc5d8aa55f51a9d1a2aa8
1 /*======================================================================
3 PCMCIA Card Information Structure parser
5 cistpl.c 1.74 1999/11/08 20:47:02
7 The contents of this file are subject to the Mozilla Public
8 License Version 1.1 (the "License"); you may not use this file
9 except in compliance with the License. You may obtain a copy of
10 the License at http://www.mozilla.org/MPL/
12 Software distributed under the License is distributed on an "AS
13 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 implied. See the License for the specific language governing
15 rights and limitations under the License.
17 The initial developer of the original code is David A. Hinds
18 <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
19 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
21 Alternatively, the contents of this file may be used under the
22 terms of the GNU Public License version 2 (the "GPL"), in which
23 case the provisions of the GPL are applicable instead of the
24 above. If you wish to allow the use of your version of this file
25 only under the terms of the GPL and not to allow others to use
26 your version of this file under the MPL, indicate your decision
27 by deleting the provisions above and replace them with the notice
28 and other provisions required by the GPL. If you do not delete
29 the provisions above, a recipient may use your version of this
30 file under either the MPL or the GPL.
32 ======================================================================*/
34 #define __NO_VERSION__
36 #include <linux/config.h>
37 #include <linux/module.h>
38 #include <linux/kernel.h>
39 #include <linux/string.h>
40 #include <linux/major.h>
41 #include <linux/errno.h>
42 #include <linux/timer.h>
43 #include <linux/malloc.h>
44 #include <linux/mm.h>
45 #include <linux/sched.h>
46 #include <linux/pci.h>
47 #include <linux/ioport.h>
48 #include <asm/io.h>
50 #include <pcmcia/cs_types.h>
51 #include <pcmcia/bus_ops.h>
52 #include <pcmcia/ss.h>
53 #include <pcmcia/cs.h>
54 #include <pcmcia/bulkmem.h>
55 #include <pcmcia/cistpl.h>
56 #include "cs_internal.h"
57 #include "rsrc_mgr.h"
59 static const u_char mantissa[] = {
60 10, 12, 13, 15, 20, 25, 30, 35,
61 40, 45, 50, 55, 60, 70, 80, 90
64 static const u_int exponent[] = {
65 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
68 /* Convert an extended speed byte to a time in nanoseconds */
69 #define SPEED_CVT(v) \
70 (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10)
71 /* Convert a power byte to a current in 0.1 microamps */
72 #define POWER_CVT(v) \
73 (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10)
74 #define POWER_SCALE(v) (exponent[(v)&7])
76 /* Upper limit on reasonable # of tuples */
77 #define MAX_TUPLES 200
79 /*======================================================================
81 Low-level functions to read and write CIS memory. I think the
82 write routine is only useful for writing one-byte registers.
84 ======================================================================*/
86 void read_cis_mem(socket_info_t *s, int attr, u_int addr,
87 u_int len, void *ptr)
89 pccard_mem_map *mem = &s->cis_mem;
90 u_char *sys;
91 u_int inc = 1;
93 DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
94 if (setup_cis_mem(s) != 0) {
95 memset(ptr, 0xff, len);
96 return;
98 mem->flags |= MAP_ACTIVE; mem->flags &= ~MAP_ATTRIB;
99 if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
100 sys = s->cis_virt + (addr & (s->cap.map_size-1));
101 mem->card_start = addr & ~(s->cap.map_size-1);
103 for (; len > 0; sys = s->cis_virt) {
104 s->ss_entry(s->sock, SS_SetMemMap, mem);
105 DEBUG(3, "cs: %#2.2x %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
106 bus_readb(s->cap.bus, sys),
107 bus_readb(s->cap.bus, sys+inc),
108 bus_readb(s->cap.bus, sys+2*inc),
109 bus_readb(s->cap.bus, sys+3*inc),
110 bus_readb(s->cap.bus, sys+4*inc));
111 for ( ; len > 0; len--, ((u_char *)ptr)++, sys += inc) {
112 if (sys == s->cis_virt+s->cap.map_size) break;
113 *(u_char *)ptr = bus_readb(s->cap.bus, sys);
115 mem->card_start += s->cap.map_size;
119 void write_cis_mem(socket_info_t *s, int attr, u_int addr,
120 u_int len, void *ptr)
122 pccard_mem_map *mem = &s->cis_mem;
123 u_char *sys;
124 int inc = 1;
126 DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
127 if (setup_cis_mem(s) != 0) return;
128 mem->flags &= ~MAP_ATTRIB;
129 if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
130 sys = s->cis_virt + (addr & (s->cap.map_size-1));
131 mem->card_start = addr & ~(s->cap.map_size-1);
133 for (; len > 0; sys = s->cis_virt) {
134 s->ss_entry(s->sock, SS_SetMemMap, mem);
135 for ( ; len > 0; len--, ((u_char *)ptr)++, sys += inc) {
136 if (sys == s->cis_virt+s->cap.map_size) break;
137 bus_writeb(s->cap.bus, *(u_char *)ptr, sys);
139 mem->card_start += s->cap.map_size;
143 /*======================================================================
145 This is tricky... when we set up CIS memory, we try to validate
146 the memory window space allocations.
148 ======================================================================*/
150 /* Scratch pointer to the socket we use for validation */
151 static socket_info_t *vs = NULL;
153 /* Validation function for cards with a valid CIS */
154 static int cis_readable(u_long base)
156 cisinfo_t info1, info2;
157 int ret;
158 vs->cis_mem.sys_start = base;
159 vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
160 vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size);
161 ret = pcmcia_validate_cis(vs->clients, &info1);
162 /* invalidate mapping and CIS cache */
163 bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0;
164 if ((ret != 0) || (info1.Chains == 0))
165 return 0;
166 vs->cis_mem.sys_start = base+vs->cap.map_size;
167 vs->cis_mem.sys_stop = base+2*vs->cap.map_size-1;
168 vs->cis_virt = bus_ioremap(vs->cap.bus, base+vs->cap.map_size,
169 vs->cap.map_size);
170 ret = pcmcia_validate_cis(vs->clients, &info2);
171 bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0;
172 return ((ret == 0) && (info1.Chains == info2.Chains));
175 /* Validation function for simple memory cards */
176 static int checksum(u_long base)
178 int i, a, b, d;
179 vs->cis_mem.sys_start = base;
180 vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
181 vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size);
182 vs->cis_mem.card_start = 0;
183 vs->cis_mem.flags = MAP_ACTIVE;
184 vs->ss_entry(vs->sock, SS_SetMemMap, &vs->cis_mem);
185 /* Don't bother checking every word... */
186 a = 0; b = -1;
187 for (i = 0; i < vs->cap.map_size; i += 44) {
188 d = bus_readl(vs->cap.bus, vs->cis_virt+i);
189 a += d; b &= d;
191 bus_iounmap(vs->cap.bus, vs->cis_virt);
192 return (b == -1) ? -1 : (a>>1);
195 static int checksum_match(u_long base)
197 int a = checksum(base), b = checksum(base+vs->cap.map_size);
198 return ((a == b) && (a >= 0));
201 int setup_cis_mem(socket_info_t *s)
203 if (s->cis_mem.sys_start == 0) {
204 int low = !(s->cap.features & SS_CAP_PAGE_REGS);
205 vs = s;
206 validate_mem(cis_readable, checksum_match, low);
207 s->cis_mem.sys_start = 0;
208 vs = NULL;
209 if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
210 s->cap.map_size, low, "card services")) {
211 printk(KERN_NOTICE "cs: unable to map card memory!\n");
212 return CS_OUT_OF_RESOURCE;
214 s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1;
215 s->cis_mem.flags |= MAP_ACTIVE;
216 s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start,
217 s->cap.map_size);
219 return 0;
222 void release_cis_mem(socket_info_t *s)
224 if (s->cis_mem.sys_start != 0) {
225 s->cis_mem.flags &= ~MAP_ACTIVE;
226 s->ss_entry(s->sock, SS_SetMemMap, &s->cis_mem);
227 release_mem_region(s->cis_mem.sys_start, s->cap.map_size);
228 bus_iounmap(s->cap.bus, s->cis_virt);
229 s->cis_mem.sys_start = 0;
233 /*======================================================================
235 This is a wrapper around read_cis_mem, with the same interface,
236 but which caches information, for cards whose CIS may not be
237 readable all the time.
239 ======================================================================*/
241 static void read_cis_cache(socket_info_t *s, int attr, u_int addr,
242 u_int len, void *ptr)
244 int i;
245 char *caddr;
247 if (s->fake_cis) {
248 if (s->fake_cis_len > addr+len)
249 memcpy(ptr, s->fake_cis+addr, len);
250 else
251 memset(ptr, 0xff, len);
252 return;
254 caddr = s->cis_cache;
255 for (i = 0; i < s->cis_used; i++) {
256 if ((s->cis_table[i].addr == addr) &&
257 (s->cis_table[i].len == len) &&
258 (s->cis_table[i].attr == attr)) break;
259 caddr += s->cis_table[i].len;
261 if (i < s->cis_used) {
262 memcpy(ptr, caddr, len);
263 return;
265 #ifdef CONFIG_CARDBUS
266 if (s->state & SOCKET_CARDBUS)
267 read_cb_mem(s, 0, attr, addr, len, ptr);
268 else
269 #endif
270 read_cis_mem(s, attr, addr, len, ptr);
271 /* Copy data into the cache, if there is room */
272 if ((i < MAX_CIS_TABLE) &&
273 (caddr+len < s->cis_cache+MAX_CIS_DATA)) {
274 s->cis_table[i].addr = addr;
275 s->cis_table[i].len = len;
276 s->cis_table[i].attr = attr;
277 s->cis_used++;
278 memcpy(caddr, ptr, len);
282 /*======================================================================
284 This verifies if the CIS of a card matches what is in the CIS
285 cache.
287 ======================================================================*/
289 int verify_cis_cache(socket_info_t *s)
291 char buf[256], *caddr;
292 int i;
294 caddr = s->cis_cache;
295 for (i = 0; i < s->cis_used; i++) {
296 #ifdef CONFIG_CARDBUS
297 if (s->state & SOCKET_CARDBUS)
298 read_cb_mem(s, 0, s->cis_table[i].attr, s->cis_table[i].addr,
299 s->cis_table[i].len, buf);
300 else
301 #endif
302 read_cis_mem(s, s->cis_table[i].attr, s->cis_table[i].addr,
303 s->cis_table[i].len, buf);
304 if (memcmp(buf, caddr, s->cis_table[i].len) != 0)
305 break;
306 caddr += s->cis_table[i].len;
308 return (i < s->cis_used);
311 /*======================================================================
313 For really bad cards, we provide a facility for uploading a
314 replacement CIS.
316 ======================================================================*/
318 int pcmcia_replace_cis(client_handle_t handle, cisdump_t *cis)
320 socket_info_t *s;
321 if (CHECK_HANDLE(handle))
322 return CS_BAD_HANDLE;
323 s = SOCKET(handle);
324 if (s->fake_cis != NULL) {
325 kfree(s->fake_cis);
326 s->fake_cis = NULL;
328 if (cis->Length > CISTPL_MAX_CIS_SIZE)
329 return CS_BAD_SIZE;
330 s->fake_cis = kmalloc(cis->Length, GFP_KERNEL);
331 if (s->fake_cis == NULL)
332 return CS_OUT_OF_RESOURCE;
333 s->fake_cis_len = cis->Length;
334 memcpy(s->fake_cis, cis->Data, cis->Length);
335 return CS_SUCCESS;
338 /*======================================================================
340 The high-level CIS tuple services
342 ======================================================================*/
344 typedef struct tuple_flags {
345 u_int link_space:3;
346 u_int has_link:1;
347 u_int mfc_fn:3;
348 u_int space:3;
349 } tuple_flags;
351 #define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space)
352 #define HAS_LINK(f) (((tuple_flags *)(&(f)))->has_link)
353 #define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn)
354 #define SPACE(f) (((tuple_flags *)(&(f)))->space)
356 int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple);
358 int pcmcia_get_first_tuple(client_handle_t handle, tuple_t *tuple)
360 socket_info_t *s;
361 if (CHECK_HANDLE(handle))
362 return CS_BAD_HANDLE;
363 s = SOCKET(handle);
364 if (!(s->state & SOCKET_PRESENT))
365 return CS_NO_CARD;
366 tuple->TupleLink = tuple->Flags = 0;
367 #ifdef CONFIG_CARDBUS
368 if (s->state & SOCKET_CARDBUS) {
369 u_int ptr;
370 pcibios_read_config_dword(s->cap.cardbus, 0, 0x28, &ptr);
371 tuple->CISOffset = ptr & ~7;
372 SPACE(tuple->Flags) = (ptr & 7);
373 } else
374 #endif
376 /* Assume presence of a LONGLINK_C to address 0 */
377 tuple->CISOffset = tuple->LinkOffset = 0;
378 SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1;
380 if (!(s->state & SOCKET_CARDBUS) && (s->functions > 1) &&
381 !(tuple->Attributes & TUPLE_RETURN_COMMON)) {
382 cisdata_t req = tuple->DesiredTuple;
383 tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
384 if (pcmcia_get_next_tuple(handle, tuple) == CS_SUCCESS) {
385 tuple->DesiredTuple = CISTPL_LINKTARGET;
386 if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
387 return CS_NO_MORE_ITEMS;
388 } else
389 tuple->CISOffset = tuple->TupleLink = 0;
390 tuple->DesiredTuple = req;
392 return pcmcia_get_next_tuple(handle, tuple);
395 static int follow_link(socket_info_t *s, tuple_t *tuple)
397 u_char link[5];
398 u_int ofs;
400 if (MFC_FN(tuple->Flags)) {
401 /* Get indirect link from the MFC tuple */
402 read_cis_cache(s, LINK_SPACE(tuple->Flags),
403 tuple->LinkOffset, 5, link);
404 ofs = le32_to_cpu(*(u_int *)(link+1));
405 SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
406 /* Move to the next indirect link */
407 tuple->LinkOffset += 5;
408 MFC_FN(tuple->Flags)--;
409 } else if (HAS_LINK(tuple->Flags)) {
410 ofs = tuple->LinkOffset;
411 SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
412 HAS_LINK(tuple->Flags) = 0;
413 } else {
414 return -1;
416 if (!(s->state & SOCKET_CARDBUS) && SPACE(tuple->Flags)) {
417 /* This is ugly, but a common CIS error is to code the long
418 link offset incorrectly, so we check the right spot... */
419 read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
420 if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
421 (strncmp(link+2, "CIS", 3) == 0))
422 return ofs;
423 /* Then, we try the wrong spot... */
424 ofs = ofs >> 1;
426 read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
427 if ((link[0] != CISTPL_LINKTARGET) || (link[1] < 3) ||
428 (strncmp(link+2, "CIS", 3) != 0))
429 return -1;
430 return ofs;
433 int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple)
435 socket_info_t *s;
436 u_char link[2], tmp;
437 int ofs, i, attr;
439 if (CHECK_HANDLE(handle))
440 return CS_BAD_HANDLE;
441 s = SOCKET(handle);
442 if (!(s->state & SOCKET_PRESENT))
443 return CS_NO_CARD;
445 link[1] = tuple->TupleLink;
446 ofs = tuple->CISOffset + tuple->TupleLink;
447 attr = SPACE(tuple->Flags);
449 for (i = 0; i < MAX_TUPLES; i++) {
450 if (link[1] == 0xff) {
451 link[0] = CISTPL_END;
452 } else {
453 read_cis_cache(s, attr, ofs, 2, link);
454 if (link[0] == CISTPL_NULL) {
455 ofs++; continue;
459 /* End of chain? Follow long link if possible */
460 if (link[0] == CISTPL_END) {
461 if ((ofs = follow_link(s, tuple)) < 0)
462 return CS_NO_MORE_ITEMS;
463 attr = SPACE(tuple->Flags);
464 read_cis_cache(s, attr, ofs, 2, link);
467 /* Is this a link tuple? Make a note of it */
468 if ((link[0] == CISTPL_LONGLINK_A) ||
469 (link[0] == CISTPL_LONGLINK_C) ||
470 (link[0] == CISTPL_LONGLINK_MFC) ||
471 (link[0] == CISTPL_LINKTARGET) ||
472 (link[0] == CISTPL_NO_LINK)) {
473 switch (link[0]) {
474 case CISTPL_LONGLINK_A:
475 HAS_LINK(tuple->Flags) = 1;
476 LINK_SPACE(tuple->Flags) = 1;
477 read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
478 break;
479 case CISTPL_LONGLINK_C:
480 HAS_LINK(tuple->Flags) = 1;
481 LINK_SPACE(tuple->Flags) = 0;
482 read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
483 break;
484 case CISTPL_LONGLINK_MFC:
485 tuple->LinkOffset = ofs + 3;
486 LINK_SPACE(tuple->Flags) = attr;
487 if (handle->Function == BIND_FN_ALL) {
488 /* Follow all the MFC links */
489 read_cis_cache(s, attr, ofs+2, 1, &tmp);
490 MFC_FN(tuple->Flags) = tmp;
491 } else {
492 /* Follow exactly one of the links */
493 MFC_FN(tuple->Flags) = 1;
494 tuple->LinkOffset += handle->Function * 5;
496 break;
497 case CISTPL_NO_LINK:
498 HAS_LINK(tuple->Flags) = 0;
499 break;
501 if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
502 (tuple->DesiredTuple == RETURN_FIRST_TUPLE))
503 break;
504 } else
505 if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
506 break;
508 if (link[0] == tuple->DesiredTuple)
509 break;
510 ofs += link[1] + 2;
512 if (i == MAX_TUPLES) {
513 DEBUG(1, "cs: overrun in pcmcia_get_next_tuple for socket %d\n",
514 handle->Socket);
515 return CS_NO_MORE_ITEMS;
518 tuple->TupleCode = link[0];
519 tuple->TupleLink = link[1];
520 tuple->CISOffset = ofs + 2;
521 return CS_SUCCESS;
524 /*====================================================================*/
526 #define _MIN(a, b) (((a) < (b)) ? (a) : (b))
528 int pcmcia_get_tuple_data(client_handle_t handle, tuple_t *tuple)
530 socket_info_t *s;
531 u_int len;
533 if (CHECK_HANDLE(handle))
534 return CS_BAD_HANDLE;
536 s = SOCKET(handle);
538 if (tuple->TupleLink < tuple->TupleOffset)
539 return CS_NO_MORE_ITEMS;
540 len = tuple->TupleLink - tuple->TupleOffset;
541 tuple->TupleDataLen = tuple->TupleLink;
542 if (len == 0)
543 return CS_SUCCESS;
544 read_cis_cache(s, SPACE(tuple->Flags),
545 tuple->CISOffset + tuple->TupleOffset,
546 _MIN(len, tuple->TupleDataMax), tuple->TupleData);
547 return CS_SUCCESS;
550 /*======================================================================
552 Parsing routines for individual tuples
554 ======================================================================*/
556 static int parse_device(tuple_t *tuple, cistpl_device_t *device)
558 int i;
559 u_char scale;
560 u_char *p, *q;
562 p = (u_char *)tuple->TupleData;
563 q = p + tuple->TupleDataLen;
565 device->ndev = 0;
566 for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
568 if (*p == 0xff) break;
569 device->dev[i].type = (*p >> 4);
570 device->dev[i].wp = (*p & 0x08) ? 1 : 0;
571 switch (*p & 0x07) {
572 case 0: device->dev[i].speed = 0; break;
573 case 1: device->dev[i].speed = 250; break;
574 case 2: device->dev[i].speed = 200; break;
575 case 3: device->dev[i].speed = 150; break;
576 case 4: device->dev[i].speed = 100; break;
577 case 7:
578 if (++p == q) return CS_BAD_TUPLE;
579 if (p == q)
580 return CS_BAD_TUPLE;
581 device->dev[i].speed = SPEED_CVT(*p);
582 while (*p & 0x80)
583 if (++p == q) return CS_BAD_TUPLE;
584 break;
585 default:
586 return CS_BAD_TUPLE;
589 if (++p == q) return CS_BAD_TUPLE;
590 if (*p == 0xff) break;
591 scale = *p & 7;
592 if (scale == 7) return CS_BAD_TUPLE;
593 device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
594 device->ndev++;
595 if (++p == q) break;
598 return CS_SUCCESS;
601 /*====================================================================*/
603 static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
605 u_char *p;
606 if (tuple->TupleDataLen < 5)
607 return CS_BAD_TUPLE;
608 p = (u_char *)tuple->TupleData;
609 csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2;
610 csum->len = le16_to_cpu(*(u_short *)(p + 2));
611 csum->sum = *(p+4);
612 return CS_SUCCESS;
615 /*====================================================================*/
617 static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
619 if (tuple->TupleDataLen < 4)
620 return CS_BAD_TUPLE;
621 link->addr = le32_to_cpu(*(u_int *)tuple->TupleData);
622 return CS_SUCCESS;
625 /*====================================================================*/
627 static int parse_longlink_mfc(tuple_t *tuple,
628 cistpl_longlink_mfc_t *link)
630 u_char *p;
631 int i;
633 p = (u_char *)tuple->TupleData;
635 link->nfn = *p; p++;
636 if (tuple->TupleDataLen <= link->nfn*5)
637 return CS_BAD_TUPLE;
638 for (i = 0; i < link->nfn; i++) {
639 link->fn[i].space = *p; p++;
640 link->fn[i].addr = le32_to_cpu(*(u_int *)p); p += 4;
642 return CS_SUCCESS;
645 /*====================================================================*/
647 static int parse_strings(u_char *p, u_char *q, int max,
648 char *s, u_char *ofs, u_char *found)
650 int i, j, ns;
652 if (p == q) return CS_BAD_TUPLE;
653 ns = 0; j = 0;
654 for (i = 0; i < max; i++) {
655 if (*p == 0xff) break;
656 ofs[i] = j;
657 ns++;
658 for (;;) {
659 s[j++] = (*p == 0xff) ? '\0' : *p;
660 if ((*p == '\0') || (*p == 0xff)) break;
661 if (++p == q) return CS_BAD_TUPLE;
663 if ((*p == 0xff) || (++p == q)) break;
665 if (found) {
666 *found = ns;
667 return CS_SUCCESS;
668 } else {
669 return (ns == max) ? CS_SUCCESS : CS_BAD_TUPLE;
673 /*====================================================================*/
675 static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
677 u_char *p, *q;
679 p = (u_char *)tuple->TupleData;
680 q = p + tuple->TupleDataLen;
682 vers_1->major = *p; p++;
683 vers_1->minor = *p; p++;
684 if (p >= q) return CS_BAD_TUPLE;
686 return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
687 vers_1->str, vers_1->ofs, &vers_1->ns);
690 /*====================================================================*/
692 static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
694 u_char *p, *q;
696 p = (u_char *)tuple->TupleData;
697 q = p + tuple->TupleDataLen;
699 return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
700 altstr->str, altstr->ofs, &altstr->ns);
703 /*====================================================================*/
705 static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
707 u_char *p, *q;
708 int nid;
710 p = (u_char *)tuple->TupleData;
711 q = p + tuple->TupleDataLen;
713 for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
714 if (p > q-2) break;
715 jedec->id[nid].mfr = p[0];
716 jedec->id[nid].info = p[1];
717 p += 2;
719 jedec->nid = nid;
720 return CS_SUCCESS;
723 /*====================================================================*/
725 static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
727 u_short *p;
728 if (tuple->TupleDataLen < 4)
729 return CS_BAD_TUPLE;
730 p = (u_short *)tuple->TupleData;
731 m->manf = le16_to_cpu(p[0]);
732 m->card = le16_to_cpu(p[1]);
733 return CS_SUCCESS;
736 /*====================================================================*/
738 static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
740 u_char *p;
741 if (tuple->TupleDataLen < 2)
742 return CS_BAD_TUPLE;
743 p = (u_char *)tuple->TupleData;
744 f->func = p[0];
745 f->sysinit = p[1];
746 return CS_SUCCESS;
749 /*====================================================================*/
751 static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
753 u_char *p;
754 int i;
755 if (tuple->TupleDataLen < 1)
756 return CS_BAD_TUPLE;
757 p = (u_char *)tuple->TupleData;
758 f->type = p[0];
759 for (i = 1; i < tuple->TupleDataLen; i++)
760 f->data[i-1] = p[i];
761 return CS_SUCCESS;
764 /*====================================================================*/
766 static int parse_config(tuple_t *tuple, cistpl_config_t *config)
768 int rasz, rmsz, i;
769 u_char *p;
771 p = (u_char *)tuple->TupleData;
772 rasz = *p & 0x03;
773 rmsz = (*p & 0x3c) >> 2;
774 if (tuple->TupleDataLen < rasz+rmsz+4)
775 return CS_BAD_TUPLE;
776 config->last_idx = *(++p);
777 p++;
778 config->base = 0;
779 for (i = 0; i <= rasz; i++)
780 config->base += p[i] << (8*i);
781 p += rasz+1;
782 for (i = 0; i < 4; i++)
783 config->rmask[i] = 0;
784 for (i = 0; i <= rmsz; i++)
785 config->rmask[i>>2] += p[i] << (8*(i%4));
786 config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
787 return CS_SUCCESS;
790 /*======================================================================
792 The following routines are all used to parse the nightmarish
793 config table entries.
795 ======================================================================*/
797 static u_char *parse_power(u_char *p, u_char *q,
798 cistpl_power_t *pwr)
800 int i;
801 u_int scale;
803 if (p == q) return NULL;
804 pwr->present = *p;
805 pwr->flags = 0;
806 p++;
807 for (i = 0; i < 7; i++)
808 if (pwr->present & (1<<i)) {
809 if (p == q) return NULL;
810 pwr->param[i] = POWER_CVT(*p);
811 scale = POWER_SCALE(*p);
812 while (*p & 0x80) {
813 if (++p == q) return NULL;
814 if ((*p & 0x7f) < 100)
815 pwr->param[i] += (*p & 0x7f) * scale / 100;
816 else if (*p == 0x7d)
817 pwr->flags |= CISTPL_POWER_HIGHZ_OK;
818 else if (*p == 0x7e)
819 pwr->param[i] = 0;
820 else if (*p == 0x7f)
821 pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
822 else
823 return NULL;
825 p++;
827 return p;
830 /*====================================================================*/
832 static u_char *parse_timing(u_char *p, u_char *q,
833 cistpl_timing_t *timing)
835 u_char scale;
837 if (p == q) return NULL;
838 scale = *p;
839 if ((scale & 3) != 3) {
840 if (++p == q) return NULL;
841 timing->wait = SPEED_CVT(*p);
842 timing->waitscale = exponent[scale & 3];
843 } else
844 timing->wait = 0;
845 scale >>= 2;
846 if ((scale & 7) != 7) {
847 if (++p == q) return NULL;
848 timing->ready = SPEED_CVT(*p);
849 timing->rdyscale = exponent[scale & 7];
850 } else
851 timing->ready = 0;
852 scale >>= 3;
853 if (scale != 7) {
854 if (++p == q) return NULL;
855 timing->reserved = SPEED_CVT(*p);
856 timing->rsvscale = exponent[scale];
857 } else
858 timing->reserved = 0;
859 p++;
860 return p;
863 /*====================================================================*/
865 static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
867 int i, j, bsz, lsz;
869 if (p == q) return NULL;
870 io->flags = *p;
872 if (!(*p & 0x80)) {
873 io->nwin = 1;
874 io->win[0].base = 0;
875 io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
876 return p+1;
879 if (++p == q) return NULL;
880 io->nwin = (*p & 0x0f) + 1;
881 bsz = (*p & 0x30) >> 4;
882 if (bsz == 3) bsz++;
883 lsz = (*p & 0xc0) >> 6;
884 if (lsz == 3) lsz++;
885 p++;
887 for (i = 0; i < io->nwin; i++) {
888 io->win[i].base = 0;
889 io->win[i].len = 1;
890 for (j = 0; j < bsz; j++, p++) {
891 if (p == q) return NULL;
892 io->win[i].base += *p << (j*8);
894 for (j = 0; j < lsz; j++, p++) {
895 if (p == q) return NULL;
896 io->win[i].len += *p << (j*8);
899 return p;
902 /*====================================================================*/
904 static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
906 int i, j, asz, lsz, has_ha;
907 u_int len, ca, ha;
909 if (p == q) return NULL;
911 mem->nwin = (*p & 0x07) + 1;
912 lsz = (*p & 0x18) >> 3;
913 asz = (*p & 0x60) >> 5;
914 has_ha = (*p & 0x80);
915 if (++p == q) return NULL;
917 for (i = 0; i < mem->nwin; i++) {
918 len = ca = ha = 0;
919 for (j = 0; j < lsz; j++, p++) {
920 if (p == q) return NULL;
921 len += *p << (j*8);
923 for (j = 0; j < asz; j++, p++) {
924 if (p == q) return NULL;
925 ca += *p << (j*8);
927 if (has_ha)
928 for (j = 0; j < asz; j++, p++) {
929 if (p == q) return NULL;
930 ha += *p << (j*8);
932 mem->win[i].len = len << 8;
933 mem->win[i].card_addr = ca << 8;
934 mem->win[i].host_addr = ha << 8;
936 return p;
939 /*====================================================================*/
941 static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
943 if (p == q) return NULL;
944 irq->IRQInfo1 = *p; p++;
945 if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
946 if (p+2 > q) return NULL;
947 irq->IRQInfo2 = (p[1]<<8) + p[0];
948 p += 2;
950 return p;
953 /*====================================================================*/
955 static int parse_cftable_entry(tuple_t *tuple,
956 cistpl_cftable_entry_t *entry)
958 u_char *p, *q, features;
960 p = tuple->TupleData;
961 q = p + tuple->TupleDataLen;
962 entry->index = *p & 0x3f;
963 entry->flags = 0;
964 if (*p & 0x40)
965 entry->flags |= CISTPL_CFTABLE_DEFAULT;
966 if (*p & 0x80) {
967 if (++p == q) return CS_BAD_TUPLE;
968 if (*p & 0x10)
969 entry->flags |= CISTPL_CFTABLE_BVDS;
970 if (*p & 0x20)
971 entry->flags |= CISTPL_CFTABLE_WP;
972 if (*p & 0x40)
973 entry->flags |= CISTPL_CFTABLE_RDYBSY;
974 if (*p & 0x80)
975 entry->flags |= CISTPL_CFTABLE_MWAIT;
976 entry->interface = *p & 0x0f;
977 } else
978 entry->interface = 0;
980 /* Process optional features */
981 if (++p == q) return CS_BAD_TUPLE;
982 features = *p; p++;
984 /* Power options */
985 if ((features & 3) > 0) {
986 p = parse_power(p, q, &entry->vcc);
987 if (p == NULL) return CS_BAD_TUPLE;
988 } else
989 entry->vcc.present = 0;
990 if ((features & 3) > 1) {
991 p = parse_power(p, q, &entry->vpp1);
992 if (p == NULL) return CS_BAD_TUPLE;
993 } else
994 entry->vpp1.present = 0;
995 if ((features & 3) > 2) {
996 p = parse_power(p, q, &entry->vpp2);
997 if (p == NULL) return CS_BAD_TUPLE;
998 } else
999 entry->vpp2.present = 0;
1001 /* Timing options */
1002 if (features & 0x04) {
1003 p = parse_timing(p, q, &entry->timing);
1004 if (p == NULL) return CS_BAD_TUPLE;
1005 } else {
1006 entry->timing.wait = 0;
1007 entry->timing.ready = 0;
1008 entry->timing.reserved = 0;
1011 /* I/O window options */
1012 if (features & 0x08) {
1013 p = parse_io(p, q, &entry->io);
1014 if (p == NULL) return CS_BAD_TUPLE;
1015 } else
1016 entry->io.nwin = 0;
1018 /* Interrupt options */
1019 if (features & 0x10) {
1020 p = parse_irq(p, q, &entry->irq);
1021 if (p == NULL) return CS_BAD_TUPLE;
1022 } else
1023 entry->irq.IRQInfo1 = 0;
1025 switch (features & 0x60) {
1026 case 0x00:
1027 entry->mem.nwin = 0;
1028 break;
1029 case 0x20:
1030 entry->mem.nwin = 1;
1031 entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
1032 entry->mem.win[0].card_addr = 0;
1033 entry->mem.win[0].host_addr = 0;
1034 p += 2;
1035 if (p > q) return CS_BAD_TUPLE;
1036 break;
1037 case 0x40:
1038 entry->mem.nwin = 1;
1039 entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
1040 entry->mem.win[0].card_addr =
1041 le16_to_cpu(*(u_short *)(p+2)) << 8;
1042 entry->mem.win[0].host_addr = 0;
1043 p += 4;
1044 if (p > q) return CS_BAD_TUPLE;
1045 break;
1046 case 0x60:
1047 p = parse_mem(p, q, &entry->mem);
1048 if (p == NULL) return CS_BAD_TUPLE;
1049 break;
1052 /* Misc features */
1053 if (features & 0x80) {
1054 if (p == q) return CS_BAD_TUPLE;
1055 entry->flags |= (*p << 8);
1056 while (*p & 0x80)
1057 if (++p == q) return CS_BAD_TUPLE;
1058 p++;
1061 entry->subtuples = q-p;
1063 return CS_SUCCESS;
1066 /*====================================================================*/
1068 #ifdef CONFIG_CARDBUS
1070 static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar)
1072 u_char *p;
1073 if (tuple->TupleDataLen < 6)
1074 return CS_BAD_TUPLE;
1075 p = (u_char *)tuple->TupleData;
1076 bar->attr = *p;
1077 p += 2;
1078 bar->size = le32_to_cpu(*(u_int *)p);
1079 return CS_SUCCESS;
1082 static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
1084 u_char *p;
1086 p = (u_char *)tuple->TupleData;
1087 if ((*p != 3) || (tuple->TupleDataLen < 6))
1088 return CS_BAD_TUPLE;
1089 config->last_idx = *(++p);
1090 p++;
1091 config->base = le32_to_cpu(*(u_int *)p);
1092 config->subtuples = tuple->TupleDataLen - 6;
1093 return CS_SUCCESS;
1096 static int parse_cftable_entry_cb(tuple_t *tuple,
1097 cistpl_cftable_entry_cb_t *entry)
1099 u_char *p, *q, features;
1101 p = tuple->TupleData;
1102 q = p + tuple->TupleDataLen;
1103 entry->index = *p & 0x3f;
1104 entry->flags = 0;
1105 if (*p & 0x40)
1106 entry->flags |= CISTPL_CFTABLE_DEFAULT;
1108 /* Process optional features */
1109 if (++p == q) return CS_BAD_TUPLE;
1110 features = *p; p++;
1112 /* Power options */
1113 if ((features & 3) > 0) {
1114 p = parse_power(p, q, &entry->vcc);
1115 if (p == NULL) return CS_BAD_TUPLE;
1116 } else
1117 entry->vcc.present = 0;
1118 if ((features & 3) > 1) {
1119 p = parse_power(p, q, &entry->vpp1);
1120 if (p == NULL) return CS_BAD_TUPLE;
1121 } else
1122 entry->vpp1.present = 0;
1123 if ((features & 3) > 2) {
1124 p = parse_power(p, q, &entry->vpp2);
1125 if (p == NULL) return CS_BAD_TUPLE;
1126 } else
1127 entry->vpp2.present = 0;
1129 /* I/O window options */
1130 if (features & 0x08) {
1131 if (p == q) return CS_BAD_TUPLE;
1132 entry->io = *p; p++;
1133 } else
1134 entry->io = 0;
1136 /* Interrupt options */
1137 if (features & 0x10) {
1138 p = parse_irq(p, q, &entry->irq);
1139 if (p == NULL) return CS_BAD_TUPLE;
1140 } else
1141 entry->irq.IRQInfo1 = 0;
1143 if (features & 0x20) {
1144 if (p == q) return CS_BAD_TUPLE;
1145 entry->mem = *p; p++;
1146 } else
1147 entry->mem = 0;
1149 /* Misc features */
1150 if (features & 0x80) {
1151 if (p == q) return CS_BAD_TUPLE;
1152 entry->flags |= (*p << 8);
1153 if (*p & 0x80) {
1154 if (++p == q) return CS_BAD_TUPLE;
1155 entry->flags |= (*p << 16);
1157 while (*p & 0x80)
1158 if (++p == q) return CS_BAD_TUPLE;
1159 p++;
1162 entry->subtuples = q-p;
1164 return CS_SUCCESS;
1167 #endif
1169 /*====================================================================*/
1171 static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
1173 u_char *p, *q;
1174 int n;
1176 p = (u_char *)tuple->TupleData;
1177 q = p + tuple->TupleDataLen;
1179 for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
1180 if (p > q-6) break;
1181 geo->geo[n].buswidth = p[0];
1182 geo->geo[n].erase_block = 1 << (p[1]-1);
1183 geo->geo[n].read_block = 1 << (p[2]-1);
1184 geo->geo[n].write_block = 1 << (p[3]-1);
1185 geo->geo[n].partition = 1 << (p[4]-1);
1186 geo->geo[n].interleave = 1 << (p[5]-1);
1187 p += 6;
1189 geo->ngeo = n;
1190 return CS_SUCCESS;
1193 /*====================================================================*/
1195 static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
1197 u_char *p, *q;
1199 if (tuple->TupleDataLen < 10)
1200 return CS_BAD_TUPLE;
1202 p = tuple->TupleData;
1203 q = p + tuple->TupleDataLen;
1205 v2->vers = p[0];
1206 v2->comply = p[1];
1207 v2->dindex = le16_to_cpu(*(u_short *)(p+2));
1208 v2->vspec8 = p[6];
1209 v2->vspec9 = p[7];
1210 v2->nhdr = p[8];
1211 p += 9;
1212 return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
1215 /*====================================================================*/
1217 static int parse_org(tuple_t *tuple, cistpl_org_t *org)
1219 u_char *p, *q;
1220 int i;
1222 p = tuple->TupleData;
1223 q = p + tuple->TupleDataLen;
1224 if (p == q) return CS_BAD_TUPLE;
1225 org->data_org = *p;
1226 if (++p == q) return CS_BAD_TUPLE;
1227 for (i = 0; i < 30; i++) {
1228 org->desc[i] = *p;
1229 if (*p == '\0') break;
1230 if (++p == q) return CS_BAD_TUPLE;
1232 return CS_SUCCESS;
1235 /*====================================================================*/
1237 int pcmcia_parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
1239 int ret = CS_SUCCESS;
1241 if (tuple->TupleDataLen > tuple->TupleDataMax)
1242 return CS_BAD_TUPLE;
1243 switch (tuple->TupleCode) {
1244 case CISTPL_DEVICE:
1245 case CISTPL_DEVICE_A:
1246 ret = parse_device(tuple, &parse->device);
1247 break;
1248 #ifdef CONFIG_CARDBUS
1249 case CISTPL_BAR:
1250 ret = parse_bar(tuple, &parse->bar);
1251 break;
1252 case CISTPL_CONFIG_CB:
1253 ret = parse_config_cb(tuple, &parse->config);
1254 break;
1255 case CISTPL_CFTABLE_ENTRY_CB:
1256 ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb);
1257 break;
1258 #endif
1259 case CISTPL_CHECKSUM:
1260 ret = parse_checksum(tuple, &parse->checksum);
1261 break;
1262 case CISTPL_LONGLINK_A:
1263 case CISTPL_LONGLINK_C:
1264 ret = parse_longlink(tuple, &parse->longlink);
1265 break;
1266 case CISTPL_LONGLINK_MFC:
1267 ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
1268 break;
1269 case CISTPL_VERS_1:
1270 ret = parse_vers_1(tuple, &parse->version_1);
1271 break;
1272 case CISTPL_ALTSTR:
1273 ret = parse_altstr(tuple, &parse->altstr);
1274 break;
1275 case CISTPL_JEDEC_A:
1276 case CISTPL_JEDEC_C:
1277 ret = parse_jedec(tuple, &parse->jedec);
1278 break;
1279 case CISTPL_MANFID:
1280 ret = parse_manfid(tuple, &parse->manfid);
1281 break;
1282 case CISTPL_FUNCID:
1283 ret = parse_funcid(tuple, &parse->funcid);
1284 break;
1285 case CISTPL_FUNCE:
1286 ret = parse_funce(tuple, &parse->funce);
1287 break;
1288 case CISTPL_CONFIG:
1289 ret = parse_config(tuple, &parse->config);
1290 break;
1291 case CISTPL_CFTABLE_ENTRY:
1292 ret = parse_cftable_entry(tuple, &parse->cftable_entry);
1293 break;
1294 case CISTPL_DEVICE_GEO:
1295 case CISTPL_DEVICE_GEO_A:
1296 ret = parse_device_geo(tuple, &parse->device_geo);
1297 break;
1298 case CISTPL_VERS_2:
1299 ret = parse_vers_2(tuple, &parse->vers_2);
1300 break;
1301 case CISTPL_ORG:
1302 ret = parse_org(tuple, &parse->org);
1303 break;
1304 case CISTPL_NO_LINK:
1305 case CISTPL_LINKTARGET:
1306 ret = CS_SUCCESS;
1307 break;
1308 default:
1309 ret = CS_UNSUPPORTED_FUNCTION;
1310 break;
1312 return ret;
1315 /*======================================================================
1317 This is used internally by Card Services to look up CIS stuff.
1319 ======================================================================*/
1321 int read_tuple(client_handle_t handle, cisdata_t code, void *parse)
1323 tuple_t tuple;
1324 cisdata_t buf[255];
1325 int ret;
1327 tuple.DesiredTuple = code;
1328 tuple.Attributes = TUPLE_RETURN_COMMON;
1329 ret = pcmcia_get_first_tuple(handle, &tuple);
1330 if (ret != CS_SUCCESS) return ret;
1331 tuple.TupleData = buf;
1332 tuple.TupleOffset = 0;
1333 tuple.TupleDataMax = sizeof(buf);
1334 ret = pcmcia_get_tuple_data(handle, &tuple);
1335 if (ret != CS_SUCCESS) return ret;
1336 ret = pcmcia_parse_tuple(handle, &tuple, parse);
1337 return ret;
1340 /*======================================================================
1342 This tries to determine if a card has a sensible CIS. It returns
1343 the number of tuples in the CIS, or 0 if the CIS looks bad. The
1344 checks include making sure several critical tuples are present and
1345 valid; seeing if the total number of tuples is reasonable; and
1346 looking for tuples that use reserved codes.
1348 ======================================================================*/
1350 int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info)
1352 tuple_t tuple;
1353 cisparse_t p;
1354 int ret, reserved, errors;
1356 if (CHECK_HANDLE(handle))
1357 return CS_BAD_HANDLE;
1359 info->Chains = reserved = errors = 0;
1360 tuple.DesiredTuple = RETURN_FIRST_TUPLE;
1361 tuple.Attributes = TUPLE_RETURN_COMMON;
1362 ret = pcmcia_get_first_tuple(handle, &tuple);
1363 if (ret != CS_SUCCESS)
1364 return CS_SUCCESS;
1366 /* First tuple should be DEVICE */
1367 if (tuple.TupleCode != CISTPL_DEVICE)
1368 errors++;
1369 /* All cards should have a MANFID tuple */
1370 if (read_tuple(handle, CISTPL_MANFID, &p) != CS_SUCCESS)
1371 errors++;
1372 /* All cards should have either a VERS_1 or a VERS_2 tuple. But
1373 at worst, we'll accept a CFTABLE_ENTRY that parses. */
1374 if ((read_tuple(handle, CISTPL_VERS_1, &p) != CS_SUCCESS) &&
1375 (read_tuple(handle, CISTPL_VERS_2, &p) != CS_SUCCESS) &&
1376 (read_tuple(handle, CISTPL_CFTABLE_ENTRY, &p) != CS_SUCCESS) &&
1377 (read_tuple(handle, CISTPL_CFTABLE_ENTRY_CB, &p) != CS_SUCCESS))
1378 errors++;
1379 if (errors > 1)
1380 return CS_SUCCESS;
1382 for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) {
1383 ret = pcmcia_get_next_tuple(handle, &tuple);
1384 if (ret != CS_SUCCESS) break;
1385 if (((tuple.TupleCode > 0x23) && (tuple.TupleCode < 0x40)) ||
1386 ((tuple.TupleCode > 0x47) && (tuple.TupleCode < 0x80)) ||
1387 ((tuple.TupleCode > 0x90) && (tuple.TupleCode < 0xff)))
1388 reserved++;
1390 if ((info->Chains == MAX_TUPLES) || (reserved > 5))
1391 info->Chains = 0;
1393 return CS_SUCCESS;