Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
428 | giacomo | 1 | /* |
2 | * drivers/pci/pci-sysfs.c |
||
3 | * |
||
4 | * (C) Copyright 2002 Greg Kroah-Hartman |
||
5 | * (C) Copyright 2002 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 = 256; |
||
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 > 256) |
||
127 | return 0; |
||
128 | if (off + count > 256) { |
||
129 | size = 256 - 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 | }, |
||
164 | .size = 256, |
||
165 | .read = pci_read_config, |
||
166 | .write = pci_write_config, |
||
167 | }; |
||
168 | |||
169 | void pci_create_sysfs_dev_files (struct pci_dev *pdev) |
||
170 | { |
||
171 | struct device *dev = &pdev->dev; |
||
172 | |||
173 | /* current configuration's attributes */ |
||
174 | device_create_file (dev, &dev_attr_vendor); |
||
175 | device_create_file (dev, &dev_attr_device); |
||
176 | device_create_file (dev, &dev_attr_subsystem_vendor); |
||
177 | device_create_file (dev, &dev_attr_subsystem_device); |
||
178 | device_create_file (dev, &dev_attr_class); |
||
179 | device_create_file (dev, &dev_attr_irq); |
||
180 | device_create_file (dev, &dev_attr_resource); |
||
181 | sysfs_create_bin_file(&dev->kobj, &pci_config_attr); |
||
182 | } |