]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/dumpcis/readcis.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / dumpcis / readcis.c
1 /*
2  * Copyright (c) 1995 Andrew McRae.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  *    derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #ifndef lint
28 static const char rcsid[] =
29   "$FreeBSD$";
30 #endif /* not lint */
31
32 /*
33  * Code cleanup, bug-fix and extension
34  * by Tatsumi Hosokawa <hosokawa@mt.cs.keio.ac.jp>
35  */
36
37 #include <err.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #include "cardinfo.h"
44 #include "cis.h"
45 #include "readcis.h"
46
47 static int ck_linktarget(int, off_t, int);
48 static struct tuple_list *read_one_tuplelist(int, int, off_t);
49 static struct tuple_list *read_tuples(int);
50 static struct tuple *find_tuple_in_list(struct tuple_list *, unsigned char);
51 static struct tuple_info *get_tuple_info(unsigned char);
52
53 static struct tuple_info tuple_info[] = {
54         {"Null tuple", CIS_NULL, 0},
55         {"Common memory descriptor", CIS_MEM_COMMON, 255},
56         {"Long link to next chain for CardBus", CIS_LONGLINK_CB, 255},
57         {"Indirect access", CIS_INDIRECT, 255},
58         {"Configuration map for CardBus", CIS_CONF_MAP_CB, 255},
59         {"Configuration entry for CardBus", CIS_CONFIG_CB, 255},
60         {"Long link to next chain for MFC", CIS_LONGLINK_MFC, 255},
61         {"Base address register for CardBus", CIS_BAR, 6},
62         {"Checksum", CIS_CHECKSUM, 5},
63         {"Long link to attribute memory", CIS_LONGLINK_A, 4},
64         {"Long link to common memory", CIS_LONGLINK_C, 4},
65         {"Link target", CIS_LINKTARGET, 3},
66         {"No link", CIS_NOLINK, 0},
67         {"Version 1 info", CIS_INFO_V1, 255},
68         {"Alternate language string", CIS_ALTSTR, 255},
69         {"Attribute memory descriptor", CIS_MEM_ATTR, 255},
70         {"JEDEC descr for common memory", CIS_JEDEC_C, 255},
71         {"JEDEC descr for attribute memory", CIS_JEDEC_A, 255},
72         {"Configuration map", CIS_CONF_MAP, 255},
73         {"Configuration entry", CIS_CONFIG, 255},
74         {"Other conditions for common memory", CIS_DEVICE_OC, 255},
75         {"Other conditions for attribute memory", CIS_DEVICE_OA, 255},
76         {"Geometry info for common memory", CIS_DEVICEGEO, 255},
77         {"Geometry info for attribute memory", CIS_DEVICEGEO_A, 255},
78         {"Manufacturer ID", CIS_MANUF_ID, 4},
79         {"Functional ID", CIS_FUNC_ID, 2},
80         {"Functional EXT", CIS_FUNC_EXT, 255},
81         {"Software interleave", CIS_SW_INTERLV, 2},
82         {"Version 2 Info", CIS_VERS_2, 255},
83         {"Data format", CIS_FORMAT, 255},
84         {"Geometry", CIS_GEOMETRY, 4},
85         {"Byte order", CIS_BYTEORDER, 2},
86         {"Card init date", CIS_DATE, 4},
87         {"Battery replacement", CIS_BATTERY, 4},
88         {"Organization", CIS_ORG, 255},
89         {"Terminator", CIS_END, 0},
90         {0, 0, 0}
91 };
92
93 static void *
94 xmalloc(int sz)
95 {
96         void   *p;
97
98         sz = (sz + 7) & ~7;
99         p = malloc(sz);
100         if (p)
101                 bzero(p, sz);
102         else
103                 errx(1, "malloc");
104         return (p);
105 }
106
107 /*
108  *      After reading the tuples, decode the relevant ones.
109  */
110 struct tuple_list *
111 readcis(int fd)
112 {
113
114         return (read_tuples(fd));
115 }
116
117 /*
118  *      free_cis - delete cis entry.
119  */
120 void
121 freecis(struct tuple_list *tlist)
122 {
123         struct tuple_list *tl;
124         struct tuple *tp;
125
126         while ((tl = tlist) != 0) {
127                 tlist = tl->next;
128                 while ((tp = tl->tuples) != 0) {
129                         tl->tuples = tp->next;
130                         free(tp->data);
131                         free(tp);
132                 }
133                 free(tl);
134         }
135 }
136
137 /*
138  *      Parse variable length value.
139  */
140 u_int
141 parse_num(int sz, u_char *p, u_char **q, int ofs)
142 {
143         u_int num = 0;
144
145         switch (sz) {   
146         case 0:
147         case 0x10:
148                 break;
149         case 1:
150         case 0x11:
151                 num = (*p++) + ofs;
152                 break;
153         case 2:
154         case 0x12:
155                 num = tpl16(p) + ofs;
156                 p += 2;
157                 break;
158         case 0x13:
159                 num = tpl24(p) + ofs;
160                 p += 3;
161                 break;
162         case 3:
163         case 0x14:
164                 num = tpl32(p) + ofs;
165                 p += 4;
166                 break;
167         }
168         if (q)
169                 *q = p;
170         return num;
171 }
172
173 /*
174  *      Read the tuples from the card.
175  *      The processing of tuples is as follows:
176  *              - Read tuples at attribute memory, offset 0.
177  *              - If a CIS_END is the first tuple, look for
178  *                a tuple list at common memory offset 0; this list
179  *                must start with a LINKTARGET.
180  *              - If a long link tuple was encountered, execute the long
181  *                link.
182  *              - If a no-link tuple was seen, terminate processing.
183  *              - If no no-link tuple exists, and no long link tuple
184  *                exists while processing the primary tuple list,
185  *                then look for a LINKTARGET tuple in common memory.
186  *              - If a long link tuple is found in any list, then process
187  *                it. Only one link is allowed per list.
188  */
189 static struct tuple_list *tlist;
190
191 static struct tuple_list *
192 read_tuples(int fd)
193 {
194         struct tuple_list *tl = 0, *last_tl;
195         struct tuple *tp;
196         int     flag;
197         off_t   offs;
198
199         tlist = 0;
200         last_tl = tlist = read_one_tuplelist(fd, MDF_ATTR, (off_t) 0);
201
202         /* Now start processing the links (if any). */
203         do {
204                 flag = MDF_ATTR;
205                 tp = find_tuple_in_list(last_tl, CIS_LONGLINK_A);
206                 if (tp == 0) {
207                         flag = 0;
208                         tp = find_tuple_in_list(last_tl, CIS_LONGLINK_C);
209                 }
210                 if (tp && tp->length == 4) {
211                         offs = tpl32(tp->data);
212 #ifdef  DEBUG
213                         printf("Checking long link at %zd (%s memory)\n",
214                             offs, flag ? "Attribute" : "Common");
215 #endif
216                         /* If a link was found, read the tuple list from it. */
217                         if (ck_linktarget(fd, offs, flag)) {
218                                 tl = read_one_tuplelist(fd, flag, offs);
219                                 last_tl->next = tl;
220                                 last_tl = tl;
221                         }
222                 } else
223                         tl = 0;
224         } while (tl);
225
226         /*
227          * If the primary list had no NOLINK tuple, and no LINKTARGET,
228          * then try to read a tuple list at common memory (offset 0).
229          */
230         if (find_tuple_in_list(tlist, CIS_NOLINK) == 0 &&
231             find_tuple_in_list(tlist, CIS_LINKTARGET) == 0 &&
232             ck_linktarget(fd, (off_t) 0, 0)) {
233                 offs = 0;
234 #ifdef  DEBUG
235                 printf("Reading long link at %zd (%s memory)\n",
236                     offs, flag ? "Attribute" : "Common");
237 #endif
238                 tlist->next = read_one_tuplelist(fd, 0, offs);
239         }
240         return (tlist);
241 }
242
243 /*
244  *      Read one tuple list from the card.
245  */
246 static struct tuple_list *
247 read_one_tuplelist(int fd, int flags, off_t offs)
248 {
249         struct tuple *tp, *last_tp = 0;
250         struct tuple_list *tl;
251         struct tuple_info *tinfo;
252         int     total = 0;
253         unsigned char code, length;
254
255         /* Check to see if this memory has already been scanned. */
256         for (tl = tlist; tl; tl = tl->next)
257                 if (tl->offs == offs && tl->flags == (flags & MDF_ATTR))
258                         return (0);
259         tl = xmalloc(sizeof(*tl));
260         tl->offs = offs;
261         tl->flags = flags & MDF_ATTR;
262         ioctl(fd, PIOCRWFLAG, &flags);
263         lseek(fd, offs, SEEK_SET);
264         do {
265                 if (read(fd, &code, 1) != 1) {
266                         warn("CIS code read");
267                         break;
268                 }
269                 total++;
270                 if (code == CIS_NULL)
271                         continue;
272                 tp = xmalloc(sizeof(*tp));
273                 tp->code = code;
274                 if (code == CIS_END)
275                         length = 0;
276                 else {
277                         if (read(fd, &length, 1) != 1) {
278                                 warn("CIS len read");
279                                 break;
280                         }
281                         total++;
282                 }
283                 tp->length = length;
284 #ifdef  DEBUG
285                 printf("Tuple code = 0x%x, len = %d\n", code, length);
286 #endif
287                 if (length == 0xFF) {
288                         length = tp->length = 0;
289                         code = CIS_END;
290                 }
291                 if (length != 0) {
292                         total += length;
293                         tp->data = xmalloc(length);
294                         if (read(fd, tp->data, length) != length) {
295                                 warn("CIS read");
296                                 break;
297                         }
298                 }
299
300                 /*
301                  * Check the tuple, and ignore it if it isn't in the table
302                  * or the length is illegal.
303                  */
304                 tinfo = get_tuple_info(code);
305                 if (tinfo != NULL && (tinfo->length != 255 && tinfo->length > length)) {
306                         printf("code %s (%d) ignored\n", tuple_name(code), code);
307                         tp->code = CIS_NULL;
308                 }
309                 if (tl->tuples == NULL)
310                         tl->tuples = tp;
311                 else
312                         last_tp->next = tp;
313                 last_tp = tp;
314         } while (code != CIS_END && total < 1024);
315         return (tl);
316 }
317
318 /*
319  *      return true if the offset points to a LINKTARGET tuple.
320  */
321 static int
322 ck_linktarget(int fd, off_t offs, int flag)
323 {
324         char    blk[5];
325
326         ioctl(fd, PIOCRWFLAG, &flag);
327         lseek(fd, offs, SEEK_SET);
328         if (read(fd, blk, 5) != 5)
329                 return (0);
330         if (blk[0] == CIS_LINKTARGET &&
331             blk[1] == 0x3 &&
332             blk[2] == 'C' &&
333             blk[3] == 'I' &&
334             blk[4] == 'S')
335                 return (1);
336         return (0);
337 }
338
339 /*
340  *      find_tuple_in_list - find a tuple within a
341  *      single tuple list.
342  */
343 static struct tuple *
344 find_tuple_in_list(struct tuple_list *tl, unsigned char code)
345 {
346         struct tuple *tp;
347
348         for (tp = tl->tuples; tp; tp = tp->next)
349                 if (tp->code == code)
350                         break;
351         return (tp);
352 }
353
354 /*
355  *      return table entry for code.
356  */
357 static struct tuple_info *
358 get_tuple_info(unsigned char code)
359 {
360         struct tuple_info *tp;
361
362         for (tp = tuple_info; tp->name; tp++)
363                 if (tp->code == code)
364                         return (tp);
365         return (0);
366 }
367
368 const char *
369 tuple_name(unsigned char code)
370 {
371         struct tuple_info *tp;
372
373         tp = get_tuple_info(code);
374         if (tp)
375                 return (tp->name);
376         return ("Unknown");
377 }