1 /* 2 * The PCI Library -- Parsing of the ID list 3 * 4 * Copyright (c) 1997--2008 Martin Mares <[email protected]> 5 * 6 * Can be freely distributed and used under the terms of the GNU GPL. 7 */ 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <errno.h> 13 14 #include "internal.h" 15 #include "names.h" 16 17 #ifdef PCI_COMPRESSED_IDS 18 #include <zlib.h> 19 typedef gzFile pci_file; 20 #define pci_gets(f, l, s) gzgets(f, l, s) 21 #define pci_eof(f) gzeof(f) 22 23 static pci_file pci_open(struct pci_access *a) 24 { 25 pci_file result; 26 size_t len; 27 char *new_name; 28 29 result = gzopen(a->id_file_name, "rb"); 30 if (result) 31 return result; 32 len = strlen(a->id_file_name); 33 if (len < 3 || memcmp(a->id_file_name + len - 3, ".gz", 3) != 0) 34 return result; 35 new_name = malloc(len - 2); 36 memcpy(new_name, a->id_file_name, len - 3); 37 new_name[len - 3] = 0; 38 pci_set_name_list_path(a, new_name, 1); 39 return gzopen(a->id_file_name, "rb"); 40 } 41 42 #define pci_close(f) gzclose(f) 43 #define PCI_ERROR(f, err) \ 44 if (!err) { \ 45 int errnum; \ 46 gzerror(f, &errnum); \ 47 if (errnum >= 0) err = NULL; \ 48 else if (errnum == Z_ERRNO) err = "I/O error"; \ 49 else err = zError(errnum); \ 50 } 51 #else 52 typedef FILE * pci_file; 53 #define pci_gets(f, l, s) fgets(l, s, f) 54 #define pci_eof(f) feof(f) 55 #define pci_open(a) fopen(a->id_file_name, "r") 56 #define pci_close(f) fclose(f) 57 #define PCI_ERROR(f, err) if (!err && ferror(f)) err = "I/O error"; 58 #endif 59 60 static int id_hex(char *p, int cnt) 61 { 62 int x = 0; 63 while (cnt--) 64 { 65 x <<= 4; 66 if (*p >= '0' && *p <= '9') 67 x += (*p - '0'); 68 else if (*p >= 'a' && *p <= 'f') 69 x += (*p - 'a' + 10); 70 else if (*p >= 'A' && *p <= 'F') 71 x += (*p - 'A' + 10); 72 else 73 return -1; 74 p++; 75 } 76 return x; 77 } 78 79 static inline int id_white_p(int c) 80 { 81 return (c == ' ') || (c == '\t'); 82 } 83 84 85 static const char *id_parse_list(struct pci_access *a, pci_file f, int *lino) 86 { 87 char line[MAX_LINE]; 88 char *p; 89 int id1=0, id2=0, id3=0, id4=0; 90 int cat = -1; 91 int nest; 92 static const char parse_error[] = "Parse error"; 93 94 *lino = 0; 95 while (pci_gets(f, line, sizeof(line))) 96 { 97 (*lino)++; 98 p = line; 99 while (*p && *p != '\n' && *p != '\r') 100 p++; 101 if (!*p && !pci_eof(f)) 102 return "Line too long"; 103 *p = 0; 104 if (p > line && (p[-1] == ' ' || p[-1] == '\t')) 105 *--p = 0; 106 107 p = line; 108 while (id_white_p(*p)) 109 p++; 110 if (!*p || *p == '#') 111 continue; 112 113 p = line; 114 while (*p == '\t') 115 p++; 116 nest = p - line; 117 118 if (!nest) /* Top-level entries */ 119 { 120 if (p[0] == 'C' && p[1] == ' ') /* Class block */ 121 { 122 if ((id1 = id_hex(p+2, 2)) < 0 || !id_white_p(p[4])) 123 return parse_error; 124 cat = ID_CLASS; 125 p += 5; 126 } 127 else if (p[0] == 'S' && p[1] == ' ') 128 { /* Generic subsystem block */ 129 if ((id1 = id_hex(p+2, 4)) < 0 || p[6]) 130 return parse_error; 131 if (!pci_id_lookup(a, 0, ID_VENDOR, id1, 0, 0, 0)) 132 return "Vendor does not exist"; 133 cat = ID_GEN_SUBSYSTEM; 134 continue; 135 } 136 else if (p[0] >= 'A' && p[0] <= 'Z' && p[1] == ' ') 137 { /* Unrecognized block (RFU) */ 138 cat = ID_UNKNOWN; 139 continue; 140 } 141 else /* Vendor ID */ 142 { 143 if ((id1 = id_hex(p, 4)) < 0 || !id_white_p(p[4])) 144 return parse_error; 145 cat = ID_VENDOR; 146 p += 5; 147 } 148 id2 = id3 = id4 = 0; 149 } 150 else if (cat == ID_UNKNOWN) /* Nested entries in RFU blocks are skipped */ 151 continue; 152 else if (nest == 1) /* Nesting level 1 */ 153 switch (cat) 154 { 155 case ID_VENDOR: 156 case ID_DEVICE: 157 case ID_SUBSYSTEM: 158 if ((id2 = id_hex(p, 4)) < 0 || !id_white_p(p[4])) 159 return parse_error; 160 p += 5; 161 cat = ID_DEVICE; 162 id3 = id4 = 0; 163 break; 164 case ID_GEN_SUBSYSTEM: 165 if ((id2 = id_hex(p, 4)) < 0 || !id_white_p(p[4])) 166 return parse_error; 167 p += 5; 168 id3 = id4 = 0; 169 break; 170 case ID_CLASS: 171 case ID_SUBCLASS: 172 case ID_PROGIF: 173 if ((id2 = id_hex(p, 2)) < 0 || !id_white_p(p[2])) 174 return parse_error; 175 p += 3; 176 cat = ID_SUBCLASS; 177 id3 = id4 = 0; 178 break; 179 default: 180 return parse_error; 181 } 182 else if (nest == 2) /* Nesting level 2 */ 183 switch (cat) 184 { 185 case ID_DEVICE: 186 case ID_SUBSYSTEM: 187 if ((id3 = id_hex(p, 4)) < 0 || !id_white_p(p[4]) || (id4 = id_hex(p+5, 4)) < 0 || !id_white_p(p[9])) 188 return parse_error; 189 p += 10; 190 cat = ID_SUBSYSTEM; 191 break; 192 case ID_CLASS: 193 case ID_SUBCLASS: 194 case ID_PROGIF: 195 if ((id3 = id_hex(p, 2)) < 0 || !id_white_p(p[2])) 196 return parse_error; 197 p += 3; 198 cat = ID_PROGIF; 199 id4 = 0; 200 break; 201 default: 202 return parse_error; 203 } 204 else /* Nesting level 3 or more */ 205 return parse_error; 206 while (id_white_p(*p)) 207 p++; 208 if (!*p) 209 return parse_error; 210 if (pci_id_insert(a, cat, id1, id2, id3, id4, p, SRC_LOCAL)) 211 return "Duplicate entry"; 212 } 213 return NULL; 214 } 215 216 int 217 pci_load_name_list(struct pci_access *a) 218 { 219 pci_file f; 220 int lino; 221 const char *err; 222 223 pci_free_name_list(a); 224 a->id_load_failed = 1; 225 if (!(f = pci_open(a))) 226 return 0; 227 err = id_parse_list(a, f, &lino); 228 PCI_ERROR(f, err); 229 pci_close(f); 230 if (err) 231 a->error("%s at %s, line %d\n", err, a->id_file_name, lino); 232 a->id_load_failed = 0; 233 return 1; 234 } 235 236 void 237 pci_free_name_list(struct pci_access *a) 238 { 239 pci_id_cache_flush(a); 240 pci_id_hash_free(a); 241 a->id_load_failed = 0; 242 } 243 244 void 245 pci_set_name_list_path(struct pci_access *a, char *name, int to_be_freed) 246 { 247 if (a->free_id_name) 248 free(a->id_file_name); 249 a->id_file_name = name; 250 a->free_id_name = to_be_freed; 251 } 252