1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
/*
* The PCI Library -- ID to Name Hash
*
* Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL v2+.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <string.h>
#include "internal.h"
#include "names.h"
struct id_bucket {
struct id_bucket *next;
unsigned int full;
};
#ifdef __GNUC__
#define BUCKET_ALIGNMENT __alignof__(struct id_bucket)
#else
union id_align {
struct id_bucket *next;
unsigned int full;
};
#define BUCKET_ALIGNMENT sizeof(union id_align)
#endif
#define BUCKET_ALIGN(n) ((n)+BUCKET_ALIGNMENT-(n)%BUCKET_ALIGNMENT)
static void *id_alloc(struct pci_access *a, unsigned int size)
{
struct id_bucket *buck = a->current_id_bucket;
unsigned int pos;
if (!a->id_hash)
{
a->id_hash = pci_malloc(a, sizeof(struct id_entry *) * HASH_SIZE);
memset(a->id_hash, 0, sizeof(struct id_entry *) * HASH_SIZE);
}
if (!buck || buck->full + size > BUCKET_SIZE)
{
buck = pci_malloc(a, BUCKET_SIZE);
buck->next = a->current_id_bucket;
a->current_id_bucket = buck;
buck->full = BUCKET_ALIGN(sizeof(struct id_bucket));
}
pos = buck->full;
buck->full = BUCKET_ALIGN(buck->full + size);
return (byte *)buck + pos;
}
static inline unsigned int id_hash(int cat, u32 id12, u32 id34)
{
unsigned int h;
h = id12 ^ (id34 << 3) ^ (cat << 5);
return h % HASH_SIZE;
}
int
pci_id_insert(struct pci_access *a, int cat, int id1, int id2, int id3, int id4, char *text, enum id_entry_src src)
{
u32 id12 = id_pair(id1, id2);
u32 id34 = id_pair(id3, id4);
unsigned int h = id_hash(cat, id12, id34);
struct id_entry *n = a->id_hash ? a->id_hash[h] : NULL;
int len = strlen(text);
while (n && (n->id12 != id12 || n->id34 != id34 || n->cat != cat))
n = n->next;
if (n)
return 1;
n = id_alloc(a, sizeof(struct id_entry) + len);
n->id12 = id12;
n->id34 = id34;
n->cat = cat;
n->src = src;
memcpy(n->name, text, len+1);
n->next = a->id_hash[h];
a->id_hash[h] = n;
return 0;
}
char
*pci_id_lookup(struct pci_access *a, int flags, int cat, int id1, int id2, int id3, int id4)
{
struct id_entry *n, *best;
u32 id12 = id_pair(id1, id2);
u32 id34 = id_pair(id3, id4);
if (a->id_hash)
{
n = a->id_hash[id_hash(cat, id12, id34)];
best = NULL;
for (; n; n=n->next)
{
if (n->id12 != id12 || n->id34 != id34 || n->cat != cat)
continue;
if (n->src == SRC_LOCAL && (flags & PCI_LOOKUP_SKIP_LOCAL))
continue;
if (n->src == SRC_NET && !(flags & PCI_LOOKUP_NETWORK))
continue;
if (n->src == SRC_CACHE && !(flags & PCI_LOOKUP_CACHE))
continue;
if (n->src == SRC_HWDB && (flags & (PCI_LOOKUP_SKIP_LOCAL | PCI_LOOKUP_NO_HWDB)))
continue;
if (!best || best->src < n->src)
best = n;
}
if (best)
return best->name;
}
return NULL;
}
void
pci_id_hash_free(struct pci_access *a)
{
pci_mfree(a->id_hash);
a->id_hash = NULL;
while (a->current_id_bucket)
{
struct id_bucket *buck = a->current_id_bucket;
a->current_id_bucket = buck->next;
pci_mfree(buck);
}
}
|