Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / drivers / pci / pci-label.c
1 /*
2  * Purpose: Export the firmware instance and label associated with
3  * a pci device to sysfs
4  * Copyright (C) 2010 Dell Inc.
5  * by Narendra K <Narendra_K@dell.com>,
6  * Jordan Hargrave <Jordan_Hargrave@dell.com>
7  *
8  * SMBIOS defines type 41 for onboard pci devices. This code retrieves
9  * the instance number and string from the type 41 record and exports
10  * it to sysfs.
11  *
12  * Please see http://linux.dell.com/wiki/index.php/Oss/libnetdevname for more
13  * information.
14  */
15
16 #include <linux/dmi.h>
17 #include <linux/sysfs.h>
18 #include <linux/pci.h>
19 #include <linux/pci_ids.h>
20 #include <linux/module.h>
21 #include <linux/device.h>
22 #include "pci.h"
23
24 enum smbios_attr_enum {
25         SMBIOS_ATTR_NONE = 0,
26         SMBIOS_ATTR_LABEL_SHOW,
27         SMBIOS_ATTR_INSTANCE_SHOW,
28 };
29
30 static mode_t
31 find_smbios_instance_string(struct pci_dev *pdev, char *buf,
32                             enum smbios_attr_enum attribute)
33 {
34         const struct dmi_device *dmi;
35         struct dmi_dev_onboard *donboard;
36         int bus;
37         int devfn;
38
39         bus = pdev->bus->number;
40         devfn = pdev->devfn;
41
42         dmi = NULL;
43         while ((dmi = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD,
44                                       NULL, dmi)) != NULL) {
45                 donboard = dmi->device_data;
46                 if (donboard && donboard->bus == bus &&
47                                         donboard->devfn == devfn) {
48                         if (buf) {
49                                 if (attribute == SMBIOS_ATTR_INSTANCE_SHOW)
50                                         return scnprintf(buf, PAGE_SIZE,
51                                                          "%d\n",
52                                                          donboard->instance);
53                                 else if (attribute == SMBIOS_ATTR_LABEL_SHOW)
54                                         return scnprintf(buf, PAGE_SIZE,
55                                                          "%s\n",
56                                                          dmi->name);
57                         }
58                         return strlen(dmi->name);
59                 }
60         }
61         return 0;
62 }
63
64 static mode_t
65 smbios_instance_string_exist(struct kobject *kobj, struct attribute *attr,
66                              int n)
67 {
68         struct device *dev;
69         struct pci_dev *pdev;
70
71         dev = container_of(kobj, struct device, kobj);
72         pdev = to_pci_dev(dev);
73
74         return find_smbios_instance_string(pdev, NULL, SMBIOS_ATTR_NONE) ?
75                                            S_IRUGO : 0;
76 }
77
78 static ssize_t
79 smbioslabel_show(struct device *dev, struct device_attribute *attr, char *buf)
80 {
81         struct pci_dev *pdev;
82         pdev = to_pci_dev(dev);
83
84         return find_smbios_instance_string(pdev, buf,
85                                            SMBIOS_ATTR_LABEL_SHOW);
86 }
87
88 static ssize_t
89 smbiosinstance_show(struct device *dev,
90                     struct device_attribute *attr, char *buf)
91 {
92         struct pci_dev *pdev;
93         pdev = to_pci_dev(dev);
94
95         return find_smbios_instance_string(pdev, buf,
96                                            SMBIOS_ATTR_INSTANCE_SHOW);
97 }
98
99 static struct device_attribute smbios_attr_label = {
100         .attr = {.name = "label", .mode = 0444},
101         .show = smbioslabel_show,
102 };
103
104 static struct device_attribute smbios_attr_instance = {
105         .attr = {.name = "index", .mode = 0444},
106         .show = smbiosinstance_show,
107 };
108
109 static struct attribute *smbios_attributes[] = {
110         &smbios_attr_label.attr,
111         &smbios_attr_instance.attr,
112         NULL,
113 };
114
115 static struct attribute_group smbios_attr_group = {
116         .attrs = smbios_attributes,
117         .is_visible = smbios_instance_string_exist,
118 };
119
120 static int
121 pci_create_smbiosname_file(struct pci_dev *pdev)
122 {
123         if (!sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group))
124                 return 0;
125         return -ENODEV;
126 }
127
128 static void
129 pci_remove_smbiosname_file(struct pci_dev *pdev)
130 {
131         sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group);
132 }
133
134 void pci_create_firmware_label_files(struct pci_dev *pdev)
135 {
136         if (!pci_create_smbiosname_file(pdev))
137                 ;
138 }
139
140 void pci_remove_firmware_label_files(struct pci_dev *pdev)
141 {
142         pci_remove_smbiosname_file(pdev);
143 }