summaryrefslogtreecommitdiffstats
path: root/drivers/pci/names.c
blob: ad224aada7c94a8567106b9772210d391483e6f5 (plain)
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
131
132
133
134
135
136
137
/*
 *	PCI Class and Device Name Tables
 *
 *	Copyright 1993--1999 Drew Eckhardt, Frederic Potter,
 *	David Mosberger-Tang, Martin Mares
 */

#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>

#ifdef CONFIG_PCI_NAMES

struct pci_device_info {
	unsigned short device;
	unsigned short seen;
	const char *name;
};

struct pci_vendor_info {
	unsigned short vendor;
	unsigned short nr;
	const char *name;
	struct pci_device_info *devices;
};

/*
 * This is ridiculous, but we want the strings in
 * the .init section so that they don't take up
 * real memory.. Parse the same file multiple times
 * to get all the info.
 */
#define VENDOR( vendor, name )		static char __vendorstr_##vendor[] __devinitdata = name;
#define ENDVENDOR()
#define DEVICE( vendor, device, name ) 	static char __devicestr_##vendor##device[] __devinitdata = name;
#include "devlist.h"


#define VENDOR( vendor, name )		static struct pci_device_info __devices_##vendor[] __devinitdata = {
#define ENDVENDOR()			};
#define DEVICE( vendor, device, name )	{ 0x##device, 0, __devicestr_##vendor##device },
#include "devlist.h"

static struct pci_vendor_info __devinitdata pci_vendor_list[] = {
#define VENDOR( vendor, name )		{ 0x##vendor, sizeof(__devices_##vendor) / sizeof(struct pci_device_info), __vendorstr_##vendor, __devices_##vendor },
#define ENDVENDOR()
#define DEVICE( vendor, device, name )
#include "devlist.h"
};

#define VENDORS (sizeof(pci_vendor_list)/sizeof(struct pci_vendor_info))

void __devinit pci_name_device(struct pci_dev *dev)
{
	const struct pci_vendor_info *vendor_p = pci_vendor_list;
	int i = VENDORS;
	char *name = dev->pretty_name;

	do {
		if (vendor_p->vendor == dev->vendor)
			goto match_vendor;
		vendor_p++;
	} while (--i);

	/* Couldn't find either the vendor nor the device */
	sprintf(name, "PCI device %04x:%04x", dev->vendor, dev->device);
	return;

	match_vendor: {
		struct pci_device_info *device_p = vendor_p->devices;
		int i = vendor_p->nr;

		while (i > 0) {
			if (device_p->device == dev->device)
				goto match_device;
			device_p++;
			i--;
		}

		/* Ok, found the vendor, but unknown device */
		sprintf(name, "PCI device %04x:%04x (%." PCI_NAME_HALF "s)",
				dev->vendor, dev->device, vendor_p->name);
		return;

		/* Full match */
		match_device: {
			char *n = name + sprintf(name, "%s %s",
					vendor_p->name, device_p->name);
			int nr = device_p->seen + 1;
			device_p->seen = nr;
			if (nr > 1)
				sprintf(n, " (#%d)", nr);
		}
	}
}

/*
 *  Class names. Not in .init section as they are needed in runtime.
 */

static u16 pci_class_numbers[] = {
#define CLASS(x,y) 0x##x,
#include "classlist.h"
};

static char *pci_class_names[] = {
#define CLASS(x,y) y,
#include "classlist.h"
};

char *
pci_class_name(u32 class)
{
	int i;

	for(i=0; i<sizeof(pci_class_numbers)/sizeof(pci_class_numbers[0]); i++)
		if (pci_class_numbers[i] == class)
			return pci_class_names[i];
	return NULL;
}

#else

void __devinit pci_name_device(struct pci_dev *dev)
{
}

char *
pci_class_name(u32 class)
{
	return NULL;
}

#endif /* CONFIG_PCI_NAMES */