ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[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 show_##field (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 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
34
35 pci_config_attr(vendor, "0x%04x\n");
36 pci_config_attr(device, "0x%04x\n");
37 pci_config_attr(subsystem_vendor, "0x%04x\n");
38 pci_config_attr(subsystem_device, "0x%04x\n");
39 pci_config_attr(class, "0x%06x\n");
40 pci_config_attr(irq, "%u\n");
41
42 /* show resources */
43 static ssize_t
44 pci_show_resources(struct device * dev, char * buf)
45 {
46         struct pci_dev * pci_dev = to_pci_dev(dev);
47         char * str = buf;
48         int i;
49         int max = 7;
50
51         if (pci_dev->subordinate)
52                 max = DEVICE_COUNT_RESOURCE;
53
54         for (i = 0; i < max; i++) {
55                 str += sprintf(str,"0x%016lx 0x%016lx 0x%016lx\n",
56                                pci_resource_start(pci_dev,i),
57                                pci_resource_end(pci_dev,i),
58                                pci_resource_flags(pci_dev,i));
59         }
60         return (str - buf);
61 }
62
63 static DEVICE_ATTR(resource,S_IRUGO,pci_show_resources,NULL);
64
65 static ssize_t
66 pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
67 {
68         struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
69         unsigned int size = 64;
70         loff_t init_off = off;
71
72         /* Several chips lock up trying to read undefined config space */
73         if (capable(CAP_SYS_ADMIN)) {
74                 size = dev->cfg_size;
75         } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
76                 size = 128;
77         }
78
79         if (off > size)
80                 return 0;
81         if (off + count > size) {
82                 size -= off;
83                 count = size;
84         } else {
85                 size = count;
86         }
87
88         while (off & 3) {
89                 unsigned char val;
90                 pci_read_config_byte(dev, off, &val);
91                 buf[off - init_off] = val;
92                 off++;
93                 if (--size == 0)
94                         break;
95         }
96
97         while (size > 3) {
98                 unsigned int val;
99                 pci_read_config_dword(dev, off, &val);
100                 buf[off - init_off] = val & 0xff;
101                 buf[off - init_off + 1] = (val >> 8) & 0xff;
102                 buf[off - init_off + 2] = (val >> 16) & 0xff;
103                 buf[off - init_off + 3] = (val >> 24) & 0xff;
104                 off += 4;
105                 size -= 4;
106         }
107
108         while (size > 0) {
109                 unsigned char val;
110                 pci_read_config_byte(dev, off, &val);
111                 buf[off - init_off] = val;
112                 off++;
113                 --size;
114         }
115
116         return count;
117 }
118
119 static ssize_t
120 pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
121 {
122         struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
123         unsigned int size = count;
124         loff_t init_off = off;
125
126         if (off > dev->cfg_size)
127                 return 0;
128         if (off + count > dev->cfg_size) {
129                 size = dev->cfg_size - off;
130                 count = size;
131         }
132
133         while (off & 3) {
134                 pci_write_config_byte(dev, off, buf[off - init_off]);
135                 off++;
136                 if (--size == 0)
137                         break;
138         }
139
140         while (size > 3) {
141                 unsigned int val = buf[off - init_off];
142                 val |= (unsigned int) buf[off - init_off + 1] << 8;
143                 val |= (unsigned int) buf[off - init_off + 2] << 16;
144                 val |= (unsigned int) buf[off - init_off + 3] << 24;
145                 pci_write_config_dword(dev, off, val);
146                 off += 4;
147                 size -= 4;
148         }
149
150         while (size > 0) {
151                 pci_write_config_byte(dev, off, buf[off - init_off]);
152                 off++;
153                 --size;
154         }
155
156         return count;
157 }
158
159 static struct bin_attribute pci_config_attr = {
160         .attr = {
161                 .name = "config",
162                 .mode = S_IRUGO | S_IWUSR,
163                 .owner = THIS_MODULE,
164         },
165         .size = 256,
166         .read = pci_read_config,
167         .write = pci_write_config,
168 };
169
170 static struct bin_attribute pcie_config_attr = {
171         .attr = {
172                 .name = "config",
173                 .mode = S_IRUGO | S_IWUSR,
174                 .owner = THIS_MODULE,
175         },
176         .size = 4096,
177         .read = pci_read_config,
178         .write = pci_write_config,
179 };
180
181 void pci_create_sysfs_dev_files (struct pci_dev *pdev)
182 {
183         struct device *dev = &pdev->dev;
184
185         /* current configuration's attributes */
186         device_create_file (dev, &dev_attr_vendor);
187         device_create_file (dev, &dev_attr_device);
188         device_create_file (dev, &dev_attr_subsystem_vendor);
189         device_create_file (dev, &dev_attr_subsystem_device);
190         device_create_file (dev, &dev_attr_class);
191         device_create_file (dev, &dev_attr_irq);
192         device_create_file (dev, &dev_attr_resource);
193
194         if (pdev->cfg_size < 4096)
195                 sysfs_create_bin_file(&dev->kobj, &pci_config_attr);
196         else
197                 sysfs_create_bin_file(&dev->kobj, &pcie_config_attr);
198
199         /* add platform-specific attributes */
200         pcibios_add_platform_entries(pdev);
201 }