VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / pci / pci-sysfs.c
1 /*
2  * drivers/pci/pci-sysfs.c
3  *
4  * (C) Copyright 2002-2004 Greg Kroah-Hartman <greg@kroah.com>
5  * (C) Copyright 2002-2004 IBM Corp.
6  * (C) Copyright 2003 Matthew Wilcox
7  * (C) Copyright 2003 Hewlett-Packard
8  *
9  * File attributes for PCI devices
10  *
11  * Modeled after usb's driverfs.c 
12  *
13  */
14
15
16 #include <linux/config.h>
17 #include <linux/kernel.h>
18 #include <linux/pci.h>
19 #include <linux/stat.h>
20
21 #include "pci.h"
22
23 /* show configuration fields */
24 #define pci_config_attr(field, format_string)                           \
25 static ssize_t                                                          \
26 field##_show(struct device *dev, char *buf)                             \
27 {                                                                       \
28         struct pci_dev *pdev;                                           \
29                                                                         \
30         pdev = to_pci_dev (dev);                                        \
31         return sprintf (buf, format_string, pdev->field);               \
32 }
33
34 pci_config_attr(vendor, "0x%04x\n");
35 pci_config_attr(device, "0x%04x\n");
36 pci_config_attr(subsystem_vendor, "0x%04x\n");
37 pci_config_attr(subsystem_device, "0x%04x\n");
38 pci_config_attr(class, "0x%06x\n");
39 pci_config_attr(irq, "%u\n");
40
41 /* show resources */
42 static ssize_t
43 resource_show(struct device * dev, char * buf)
44 {
45         struct pci_dev * pci_dev = to_pci_dev(dev);
46         char * str = buf;
47         int i;
48         int max = 7;
49
50         if (pci_dev->subordinate)
51                 max = DEVICE_COUNT_RESOURCE;
52
53         for (i = 0; i < max; i++) {
54                 str += sprintf(str,"0x%016lx 0x%016lx 0x%016lx\n",
55                                pci_resource_start(pci_dev,i),
56                                pci_resource_end(pci_dev,i),
57                                pci_resource_flags(pci_dev,i));
58         }
59         return (str - buf);
60 }
61
62 struct device_attribute pci_dev_attrs[] = {
63         __ATTR_RO(resource),
64         __ATTR_RO(vendor),
65         __ATTR_RO(device),
66         __ATTR_RO(subsystem_vendor),
67         __ATTR_RO(subsystem_device),
68         __ATTR_RO(class),
69         __ATTR_RO(irq),
70         __ATTR_NULL,
71 };
72
73 static ssize_t
74 pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
75 {
76         struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
77         unsigned int size = 64;
78         loff_t init_off = off;
79
80         /* Several chips lock up trying to read undefined config space */
81         if (capable(CAP_SYS_ADMIN)) {
82                 size = dev->cfg_size;
83         } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
84                 size = 128;
85         }
86
87         if (off > size)
88                 return 0;
89         if (off + count > size) {
90                 size -= off;
91                 count = size;
92         } else {
93                 size = count;
94         }
95
96         while (off & 3) {
97                 unsigned char val;
98                 pci_read_config_byte(dev, off, &val);
99                 buf[off - init_off] = val;
100                 off++;
101                 if (--size == 0)
102                         break;
103         }
104
105         while (size > 3) {
106                 unsigned int val;
107                 pci_read_config_dword(dev, off, &val);
108                 buf[off - init_off] = val & 0xff;
109                 buf[off - init_off + 1] = (val >> 8) & 0xff;
110                 buf[off - init_off + 2] = (val >> 16) & 0xff;
111                 buf[off - init_off + 3] = (val >> 24) & 0xff;
112                 off += 4;
113                 size -= 4;
114         }
115
116         while (size > 0) {
117                 unsigned char val;
118                 pci_read_config_byte(dev, off, &val);
119                 buf[off - init_off] = val;
120                 off++;
121                 --size;
122         }
123
124         return count;
125 }
126
127 static ssize_t
128 pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
129 {
130         struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
131         unsigned int size = count;
132         loff_t init_off = off;
133
134         if (off > dev->cfg_size)
135                 return 0;
136         if (off + count > dev->cfg_size) {
137                 size = dev->cfg_size - off;
138                 count = size;
139         }
140
141         while (off & 3) {
142                 pci_write_config_byte(dev, off, buf[off - init_off]);
143                 off++;
144                 if (--size == 0)
145                         break;
146         }
147
148         while (size > 3) {
149                 unsigned int val = buf[off - init_off];
150                 val |= (unsigned int) buf[off - init_off + 1] << 8;
151                 val |= (unsigned int) buf[off - init_off + 2] << 16;
152                 val |= (unsigned int) buf[off - init_off + 3] << 24;
153                 pci_write_config_dword(dev, off, val);
154                 off += 4;
155                 size -= 4;
156         }
157
158         while (size > 0) {
159                 pci_write_config_byte(dev, off, buf[off - init_off]);
160                 off++;
161                 --size;
162         }
163
164         return count;
165 }
166
167 static struct bin_attribute pci_config_attr = {
168         .attr = {
169                 .name = "config",
170                 .mode = S_IRUGO | S_IWUSR,
171                 .owner = THIS_MODULE,
172         },
173         .size = 256,
174         .read = pci_read_config,
175         .write = pci_write_config,
176 };
177
178 static struct bin_attribute pcie_config_attr = {
179         .attr = {
180                 .name = "config",
181                 .mode = S_IRUGO | S_IWUSR,
182                 .owner = THIS_MODULE,
183         },
184         .size = 4096,
185         .read = pci_read_config,
186         .write = pci_write_config,
187 };
188
189 void pci_create_sysfs_dev_files (struct pci_dev *pdev)
190 {
191         if (pdev->cfg_size < 4096)
192                 sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
193         else
194                 sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
195
196         /* add platform-specific attributes */
197         pcibios_add_platform_entries(pdev);
198 }