Fixed binary search: no more infinite loops when vendor is unknown.
[cake.git] / arch / common / hidd.pci / pcitool / pciids.c
blob704ff2ef6ae74f9ff783e59531fb6029884d419c
1 #include <exec/types.h>
3 #include <proto/dos.h>
5 #include "pciids.h"
7 #include <ctype.h>
8 #include <stdio.h>
10 #include <aros/debug.h>
12 // it's supposed to become a shared library one day ...
13 //
14 // current implementation:
15 // on pciids_Open(), the file is read in memory, then
16 // an index is built (in computeVendorIndexes()), as an array
17 // of couples (vendor_id, offset)
18 // where offset is the offset where the vendor stuff begins
19 // in the memory file. This array is ascending sorted by vendor_id,
20 // so a binary search can be done to retrieve the vendor offset
21 // given its id. This search is done in getVendorIndex().
22 // All the stringification functions first call this search func,
23 // then parse the memory:
24 // 1234 VendorName (so: s[0] = hex digit, s[4] == ' ', s[6+] == name)
25 // <tab>1234 DeviceName (same with a tab on linestart)
26 // todo: subvendor/subdevice parsing
27 // todo: proper memory reallocation, currently the index is fixed
28 // to 2000 vendors (around 1700 exist on 2004-02-08)
30 static STRPTR mem = NULL;
31 static ULONG memsize = 0;
33 struct vendor_cell
35 UWORD vendorID;
36 LONG offset;
39 static struct vendor_cell *vendor_index = NULL;
40 static ULONG vi_allocated = 0;
41 static UWORD vi_number = 0;
43 static LONG skip_line(const char *buffer, LONG size, LONG pos)
45 buffer += pos;
46 while (pos < size)
48 if (*buffer++ == '\n')
50 pos++;
51 break;
53 pos++;
55 return pos;
58 static LONG copy_until_eol(STRPTR m, ULONG msize, LONG pos, STRPTR buf,
59 ULONG bufsize)
61 LONG j = 0;
63 m += pos;
64 while ((pos < msize) && (j < bufsize - 1) && (*m != '\n'))
66 buf[j++] = *m++;
68 buf[j] = 0;
69 return j;
72 static BOOL computeVendorIndexes(const char *buffer, LONG size)
74 LONG i, j;
76 vi_allocated = 2000;
77 vendor_index = AllocVec(vi_allocated * sizeof(struct vendor_cell), MEMF_ANY);
78 if (NULL == vendor_index)
79 return FALSE;
81 i = 0;
82 j = 0;
84 while (i < size)
86 // dont use isxdigit, beware of uppercase letter
87 if ((isdigit(buffer[i]) || (buffer[i] >= 'a' && buffer[i] <= 'f'))
88 && (i + 4 < size) && (buffer[i + 4] == ' '))
90 if (sscanf(buffer + i, "%hx", &(vendor_index[j].vendorID)) != 1)
91 return FALSE;
92 vendor_index[j].offset = i;
93 //bug("%ld: %x => %ld\n", j, vendor_index[j].vendorID, vendor_index[j].offset);
94 j++;
95 if (j > vi_allocated)
97 bug("[pcitool] pciids.c:computeVendorIndexes: vendor_index overflow\n");
98 FreeVec(vendor_index);
99 vendor_index = NULL;
100 return FALSE;
103 i = skip_line(buffer, size, i);
105 vi_number = j - 1;
106 return TRUE;
109 static LONG getVendorIndex(UWORD vendorID)
111 LONG lower = 0;
112 LONG upper = vi_number;
114 if (!mem || !vendor_index)
115 return -1;
117 while (upper != lower)
119 UWORD vid;
121 vid = vendor_index[(upper + lower) / 2].vendorID;
122 if (vid == vendorID)
123 return vendor_index[(upper + lower) / 2].offset;
124 if (vendorID > vid)
125 lower = (upper + lower) / 2 + 1;
126 else
127 upper = (upper + lower) / 2;
129 return -1;
132 static LONG getDeviceIndex(LONG vendorIndex, UWORD deviceID)
134 LONG i = vendorIndex;
136 if (i < 0)
137 return i;
139 i = skip_line(mem, memsize, i); // skip vendor
140 while ((i < memsize) && ((mem[i] == '\t') || (mem[i] == '#')))
142 UWORD did;
144 if (mem[i] != '#')
146 if ((i + 6 < memsize) && (mem[i + 5] == ' ')
147 && (sscanf(mem + i + 1, "%hx", &did) == 1) && (did == deviceID))
149 return i;
152 i = skip_line(mem, memsize, i);
154 return -1;
157 static LONG getSubDeviceIndex(LONG deviceIndex, UWORD subVendorID, UWORD subDeviceID)
159 LONG i = deviceIndex;
161 if (i < 0)
162 return i;
164 i = skip_line(mem, memsize, i);
165 while ((i < memsize) && ((mem[i] == '\t') || (mem[i] == '#')))
167 UWORD subvid, subdid;
169 if ((mem[i] != '#') && (i + 1 < memsize) && (mem[i+1] == '\t'))
171 if ((i + 11 < memsize)
172 && (mem[i + 6] == ' ')
173 && (sscanf(mem + i, "%hx", &subvid) == 1)
174 && (subvid == subVendorID)
175 && (mem[i + 11] == ' ')
176 && (sscanf(mem + i + 7, "%hx", &subdid) == 1)
177 && (subdid == subDeviceID))
179 return i;
182 i = skip_line(mem, memsize, i);
184 return -1;
187 void pciids_Open(void)
189 APTR fh;
190 LONG size;
192 fh = Open("DEVS:pci.ids", MODE_OLDFILE);
193 if (!fh)
194 goto err_open_ids;
196 Seek(fh, 0, OFFSET_END);
197 size = Seek(fh, 0, OFFSET_CURRENT);
198 if (size <= 0)
199 goto err_size;
201 memsize = (ULONG)size;
202 Seek(fh, 0, OFFSET_BEGINNING);
204 mem = AllocVec(memsize, MEMF_ANY);
205 if (NULL == mem)
206 goto err_mem;
208 if (Read(fh, mem, memsize) != size)
209 goto err_read;
211 if (!computeVendorIndexes(mem, memsize))
212 goto err_index;
214 // success !
215 return;
217 err_index:
218 err_read:
219 FreeVec(mem);
220 mem = NULL;
221 err_mem:
222 err_size:
223 Close(fh);
224 err_open_ids:
225 return;
228 void pciids_Close(void)
230 if (vendor_index)
232 FreeVec(vendor_index);
233 vendor_index = NULL;
236 if (mem)
238 FreeVec(mem);
239 mem = NULL;
243 STRPTR pciids_GetVendorName(UWORD vendorID, STRPTR buf, ULONG bufsize)
245 LONG i = getVendorIndex(vendorID);
247 buf[0] = 0;
248 if (i < 0)
249 return buf;
251 copy_until_eol(mem, memsize, i + 6, buf, bufsize);
253 return buf;
256 STRPTR pciids_GetDeviceName(UWORD vendorID, UWORD deviceID, STRPTR buf,
257 ULONG bufsize)
259 LONG i = getVendorIndex(vendorID);
261 buf[0] = 0;
262 if (i < 0) // unknown vendor
263 return buf;
265 i = getDeviceIndex(i, deviceID);
266 if (i < 0) // unknown device
267 return buf;
269 copy_until_eol(mem, memsize, i + 7, buf, bufsize);
270 return buf;
273 STRPTR pciids_GetSubDeviceName(UWORD vendorID, UWORD deviceID, UWORD subVendorID,
274 UWORD subDeviceID, STRPTR buf, ULONG bufsize)
276 LONG i;
277 LONG j;
278 LONG copied;
280 buf[0] = 0;
282 if ((0 == subVendorID) && (0 == subDeviceID))
283 return buf;
285 i = getVendorIndex(vendorID);
286 if (i < 0) // unknown vendor
287 return buf;
289 i = getDeviceIndex(i, deviceID);
290 if (i < 0) // unknown device
291 return buf;
293 j = getVendorIndex(subVendorID);
294 if (j < 0) // unknown subvendor
295 return buf;
297 copied = copy_until_eol(mem, memsize, j + 6, buf, bufsize);
299 if (copied + 4 < bufsize)
301 strcpy(buf + copied, " : ");
303 i = getSubDeviceIndex(i, subVendorID, subDeviceID);
304 if (i < 0) // unknown subdevice
306 if (bufsize - copied - 3 > 6)
307 sprintf(buf + copied + 3, "0x%04x", subDeviceID);
308 return buf;
311 copy_until_eol(mem, memsize, i + 13, buf + copied + 3,
312 bufsize - copied - 3);
315 return buf;