Rev 9499 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 9499 | Rev 9583 | ||
---|---|---|---|
1 | #include |
1 | #include |
2 | #include |
2 | #include |
3 | #include |
3 | #include |
4 | #include |
4 | #include |
5 | #include |
5 | #include |
6 | 6 | ||
7 | #include "acpi.h" |
7 | #include "acpi.h" |
8 | #include "acpi_bus.h" |
8 | #include "acpi_bus.h" |
9 | #include "dmdev.h" |
9 | #include "dmdev.h" |
10 | 10 | ||
11 | #define PREFIX "ACPI: " |
11 | #define PREFIX "ACPI: " |
12 | 12 | ||
13 | #define ACPI_BUS_CLASS "system_bus" |
13 | #define ACPI_BUS_CLASS "system_bus" |
14 | #define ACPI_BUS_HID "KLBSYBUS" |
14 | #define ACPI_BUS_HID "KLBSYBUS" |
15 | #define ACPI_BUS_DEVICE_NAME "System Bus" |
15 | #define ACPI_BUS_DEVICE_NAME "System Bus" |
16 | 16 | ||
17 | 17 | ||
18 | #define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) |
18 | #define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) |
19 | 19 | ||
20 | LIST_HEAD(acpi_device_list); |
20 | LIST_HEAD(acpi_device_list); |
21 | LIST_HEAD(acpi_bus_id_list); |
21 | LIST_HEAD(acpi_bus_id_list); |
22 | LIST_HEAD(dmdev_tree); |
22 | LIST_HEAD(dmdev_tree); |
23 | 23 | ||
24 | 24 | ||
25 | struct acpi_device_bus_id |
25 | struct acpi_device_bus_id |
26 | { |
26 | { |
27 | char bus_id[15]; |
27 | char bus_id[15]; |
28 | unsigned int instance_no; |
28 | unsigned int instance_no; |
29 | struct list_head node; |
29 | struct list_head node; |
30 | }; |
30 | }; |
31 | 31 | ||
32 | 32 | ||
33 | #define ACPI_NS_ROOT_PATH "\\" |
33 | #define ACPI_NS_ROOT_PATH "\\" |
34 | #define ACPI_NS_SYSTEM_BUS "_SB_" |
34 | #define ACPI_NS_SYSTEM_BUS "_SB_" |
35 | 35 | ||
36 | enum acpi_irq_model_id { |
36 | enum acpi_irq_model_id { |
37 | ACPI_IRQ_MODEL_PIC = 0, |
37 | ACPI_IRQ_MODEL_PIC = 0, |
38 | ACPI_IRQ_MODEL_IOAPIC, |
38 | ACPI_IRQ_MODEL_IOAPIC, |
39 | ACPI_IRQ_MODEL_IOSAPIC, |
39 | ACPI_IRQ_MODEL_IOSAPIC, |
40 | ACPI_IRQ_MODEL_PLATFORM, |
40 | ACPI_IRQ_MODEL_PLATFORM, |
41 | ACPI_IRQ_MODEL_COUNT |
41 | ACPI_IRQ_MODEL_COUNT |
42 | }; |
42 | }; |
43 | 43 | ||
44 | enum acpi_bus_removal_type { |
44 | enum acpi_bus_removal_type { |
45 | ACPI_BUS_REMOVAL_NORMAL = 0, |
45 | ACPI_BUS_REMOVAL_NORMAL = 0, |
46 | ACPI_BUS_REMOVAL_EJECT, |
46 | ACPI_BUS_REMOVAL_EJECT, |
47 | ACPI_BUS_REMOVAL_SUPRISE, |
47 | ACPI_BUS_REMOVAL_SUPRISE, |
48 | ACPI_BUS_REMOVAL_TYPE_COUNT |
48 | ACPI_BUS_REMOVAL_TYPE_COUNT |
49 | }; |
49 | }; |
50 | 50 | ||
51 | 51 | ||
52 | #define PCI_MAX_DEVICES 32 |
52 | #define PCI_MAX_DEVICES 32 |
53 | #define PCI_MAX_PINS 4 |
53 | #define PCI_MAX_PINS 4 |
54 | 54 | ||
55 | #define IRQ_TABLE_ENTRIES (PCI_MAX_DEVICES * PCI_MAX_PINS) |
55 | #define IRQ_TABLE_ENTRIES (PCI_MAX_DEVICES * PCI_MAX_PINS) |
56 | 56 | ||
57 | static int irqtable[IRQ_TABLE_ENTRIES]; |
57 | static int irqtable[IRQ_TABLE_ENTRIES]; |
58 | static ACPI_HANDLE pci_root_handle; |
58 | static ACPI_HANDLE pci_root_handle; |
59 | 59 | ||
60 | 60 | ||
61 | #define addr_offset(addr, off) \ |
61 | #define addr_offset(addr, off) \ |
62 | (addr_t)((addr_t)(addr) + (addr_t)(off)) |
62 | (addr_t)((addr_t)(addr) + (addr_t)(off)) |
63 | 63 | ||
64 | //#define acpi_remap( addr ) \ |
64 | //#define acpi_remap( addr ) \ |
65 | // (addr_t)((addr_t)(addr) + OS_BASE) |
65 | // (addr_t)((addr_t)(addr) + OS_BASE) |
66 | 66 | ||
67 | #define acpi_remap( addr ) MapIoMem((void*)(addr),4096, 0x01) |
67 | #define acpi_remap( addr ) MapIoMem((void*)(addr),4096, 0x01) |
68 | 68 | ||
69 | char* strdup(const char *str); |
69 | char* strdup(const char *str); |
70 | int sprintf(char *buf, const char *fmt, ...); |
70 | int sprintf(char *buf, const char *fmt, ...); |
71 | 71 | ||
72 | void print_pci_irqs(); |
72 | void print_pci_irqs(); |
73 | 73 | ||
74 | 74 | ||
75 | struct acpi_device *acpi_root; |
75 | struct acpi_device *acpi_root; |
76 | 76 | ||
77 | extern struct resource iomem_resource; |
77 | extern struct resource iomem_resource; |
78 | extern struct resource ioport_resource; |
78 | extern struct resource ioport_resource; |
79 | 79 | ||
80 | enum pic_mode |
80 | enum pic_mode |
81 | { |
81 | { |
82 | IO_PIC = 0, |
82 | IO_PIC = 0, |
83 | IO_APIC |
83 | IO_APIC |
84 | }; |
84 | }; |
85 | 85 | ||
86 | static ACPI_STATUS |
86 | static ACPI_STATUS |
87 | resource_to_addr(ACPI_RESOURCE *resource, ACPI_RESOURCE_ADDRESS64 *addr); |
87 | resource_to_addr(ACPI_RESOURCE *resource, ACPI_RESOURCE_ADDRESS64 *addr); |
88 | 88 | ||
89 | static void create_dm_list(); |
89 | static void create_dm_list(); |
90 | 90 | ||
91 | static void print_dm_list(); |
91 | static void print_dm_list(); |
92 | 92 | ||
93 | int write_device_dat(char *path); |
93 | int write_device_dat(char *path); |
94 | 94 | ||
95 | 95 | ||
96 | static void set_pic_mode(enum pic_mode mode) |
96 | static void set_pic_mode(enum pic_mode mode) |
97 | { |
97 | { |
98 | ACPI_OBJECT arg1; |
98 | ACPI_OBJECT arg1; |
99 | ACPI_OBJECT_LIST args; |
99 | ACPI_OBJECT_LIST args; |
100 | ACPI_STATUS as; |
100 | ACPI_STATUS as; |
101 | 101 | ||
102 | arg1.Type = ACPI_TYPE_INTEGER; |
102 | arg1.Type = ACPI_TYPE_INTEGER; |
103 | arg1.Integer.Value = mode; |
103 | arg1.Integer.Value = mode; |
104 | args.Count = 1; |
104 | args.Count = 1; |
105 | args.Pointer = &arg1; |
105 | args.Pointer = &arg1; |
106 | 106 | ||
107 | as = AcpiEvaluateObject(ACPI_ROOT_OBJECT, "_PIC", &args, NULL); |
107 | as = AcpiEvaluateObject(ACPI_ROOT_OBJECT, "_PIC", &args, NULL); |
108 | /* |
108 | /* |
109 | * We can silently ignore failure as it may not be implemented, ACPI should |
109 | * We can silently ignore failure as it may not be implemented, ACPI should |
110 | * provide us with correct information anyway |
110 | * provide us with correct information anyway |
111 | */ |
111 | */ |
112 | if (ACPI_SUCCESS(as)) |
112 | if (ACPI_SUCCESS(as)) |
113 | dbgprintf(PREFIX "machine set to %s mode\n", mode ? "APIC" : "PIC"); |
113 | dbgprintf(PREFIX "machine set to %s mode\n", mode ? "APIC" : "PIC"); |
114 | } |
114 | } |
115 | 115 | ||
116 | 116 | ||
117 | 117 | ||
118 | static bool pci_use_crs = false; |
118 | static bool pci_use_crs = false; |
119 | 119 | ||
120 | #define IORESOURCE_BUS 0x00001000 |
120 | #define IORESOURCE_BUS 0x00001000 |
121 | 121 | ||
122 | 122 | ||
123 | extern struct list_head acpi_pci_roots; |
123 | extern struct list_head acpi_pci_roots; |
124 | 124 | ||
125 | #define ACPI_PCI_ROOT_CLASS "pci_bridge" |
125 | #define ACPI_PCI_ROOT_CLASS "pci_bridge" |
126 | #define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" |
126 | #define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" |
127 | 127 | ||
128 | static ACPI_STATUS |
128 | static ACPI_STATUS |
129 | get_root_bridge_busnr_callback(ACPI_RESOURCE *resource, void *data) |
129 | get_root_bridge_busnr_callback(ACPI_RESOURCE *resource, void *data) |
130 | { |
130 | { |
131 | struct resource *res = data; |
131 | struct resource *res = data; |
132 | ACPI_RESOURCE_ADDRESS64 address; |
132 | ACPI_RESOURCE_ADDRESS64 address; |
133 | 133 | ||
134 | if (resource->Type != ACPI_RESOURCE_TYPE_ADDRESS16 && |
134 | if (resource->Type != ACPI_RESOURCE_TYPE_ADDRESS16 && |
135 | resource->Type != ACPI_RESOURCE_TYPE_ADDRESS32 && |
135 | resource->Type != ACPI_RESOURCE_TYPE_ADDRESS32 && |
136 | resource->Type != ACPI_RESOURCE_TYPE_ADDRESS64) |
136 | resource->Type != ACPI_RESOURCE_TYPE_ADDRESS64) |
137 | return AE_OK; |
137 | return AE_OK; |
138 | 138 | ||
139 | AcpiResourceToAddress64(resource, &address); |
139 | AcpiResourceToAddress64(resource, &address); |
140 | if ((address.AddressLength > 0) && |
140 | if ((address.AddressLength > 0) && |
141 | (address.ResourceType == ACPI_BUS_NUMBER_RANGE)) { |
141 | (address.ResourceType == ACPI_BUS_NUMBER_RANGE)) { |
142 | res->start = address.Minimum; |
142 | res->start = address.Minimum; |
143 | res->end = address.Minimum + address.AddressLength - 1; |
143 | res->end = address.Minimum + address.AddressLength - 1; |
144 | } |
144 | } |
145 | 145 | ||
146 | return AE_OK; |
146 | return AE_OK; |
147 | } |
147 | } |
148 | 148 | ||
149 | 149 | ||
150 | 150 | ||
151 | static ACPI_STATUS try_get_root_bridge_busnr(ACPI_HANDLE handle, |
151 | static ACPI_STATUS try_get_root_bridge_busnr(ACPI_HANDLE handle, |
152 | struct resource *res) |
152 | struct resource *res) |
153 | { |
153 | { |
154 | ACPI_STATUS status; |
154 | ACPI_STATUS status; |
155 | 155 | ||
156 | res->start = -1; |
156 | res->start = -1; |
157 | status = |
157 | status = |
158 | AcpiWalkResources(handle, METHOD_NAME__CRS, |
158 | AcpiWalkResources(handle, METHOD_NAME__CRS, |
159 | get_root_bridge_busnr_callback, res); |
159 | get_root_bridge_busnr_callback, res); |
160 | if (ACPI_FAILURE(status)) |
160 | if (ACPI_FAILURE(status)) |
161 | return status; |
161 | return status; |
162 | if (res->start == -1) |
162 | if (res->start == -1) |
163 | return AE_ERROR; |
163 | return AE_ERROR; |
164 | return AE_OK; |
164 | return AE_OK; |
165 | } |
165 | } |
166 | 166 | ||
167 | 167 | ||
168 | static void acpi_pci_bridge_scan(struct acpi_device *device) |
168 | static void acpi_pci_bridge_scan(struct acpi_device *device) |
169 | { |
169 | { |
170 | int status; |
170 | int status; |
171 | struct acpi_device *child = NULL; |
171 | struct acpi_device *child = NULL; |
172 | 172 | ||
173 | if (device->flags.bus_address) |
173 | if (device->flags.bus_address) |
174 | if (device->parent && device->parent->ops.bind) { |
174 | if (device->parent && device->parent->ops.bind) { |
175 | status = device->parent->ops.bind(device); |
175 | status = device->parent->ops.bind(device); |
176 | if (!status) { |
176 | if (!status) { |
177 | list_for_each_entry(child, &device->children, node) |
177 | list_for_each_entry(child, &device->children, node) |
178 | acpi_pci_bridge_scan(child); |
178 | acpi_pci_bridge_scan(child); |
179 | } |
179 | } |
180 | } |
180 | } |
181 | } |
181 | } |
182 | 182 | ||
183 | 183 | ||
184 | 184 | ||
185 | struct pci_root_info |
185 | struct pci_root_info |
186 | { |
186 | { |
187 | struct acpi_device *bridge; |
187 | struct acpi_device *bridge; |
188 | char *name; |
188 | char *name; |
189 | unsigned int res_num; |
189 | unsigned int res_num; |
190 | struct resource *res; |
190 | struct resource *res; |
191 | struct pci_bus *bus; |
191 | struct pci_bus *bus; |
192 | int busnum; |
192 | int busnum; |
193 | }; |
193 | }; |
194 | 194 | ||
195 | 195 | ||
196 | static ACPI_STATUS |
196 | static ACPI_STATUS |
197 | resource_to_addr(ACPI_RESOURCE *resource, ACPI_RESOURCE_ADDRESS64 *addr) |
197 | resource_to_addr(ACPI_RESOURCE *resource, ACPI_RESOURCE_ADDRESS64 *addr) |
198 | { |
198 | { |
199 | ACPI_STATUS status; |
199 | ACPI_STATUS status; |
200 | struct acpi_resource_memory24 *memory24; |
200 | struct acpi_resource_memory24 *memory24; |
201 | struct acpi_resource_memory32 *memory32; |
201 | struct acpi_resource_memory32 *memory32; |
202 | struct acpi_resource_fixed_memory32 *fixed_memory32; |
202 | struct acpi_resource_fixed_memory32 *fixed_memory32; |
203 | 203 | ||
204 | memset(addr, 0, sizeof(*addr)); |
204 | memset(addr, 0, sizeof(*addr)); |
205 | switch (resource->Type) { |
205 | switch (resource->Type) { |
206 | case ACPI_RESOURCE_TYPE_MEMORY24: |
206 | case ACPI_RESOURCE_TYPE_MEMORY24: |
207 | memory24 = &resource->Data.Memory24; |
207 | memory24 = &resource->Data.Memory24; |
208 | addr->ResourceType = ACPI_MEMORY_RANGE; |
208 | addr->ResourceType = ACPI_MEMORY_RANGE; |
209 | addr->Minimum = memory24->Minimum; |
209 | addr->Minimum = memory24->Minimum; |
210 | addr->AddressLength = memory24->AddressLength; |
210 | addr->AddressLength = memory24->AddressLength; |
211 | addr->Maximum = addr->Minimum + addr->AddressLength - 1; |
211 | addr->Maximum = addr->Minimum + addr->AddressLength - 1; |
212 | return AE_OK; |
212 | return AE_OK; |
213 | case ACPI_RESOURCE_TYPE_MEMORY32: |
213 | case ACPI_RESOURCE_TYPE_MEMORY32: |
214 | memory32 = &resource->Data.Memory32; |
214 | memory32 = &resource->Data.Memory32; |
215 | addr->ResourceType = ACPI_MEMORY_RANGE; |
215 | addr->ResourceType = ACPI_MEMORY_RANGE; |
216 | addr->Minimum = memory32->Minimum; |
216 | addr->Minimum = memory32->Minimum; |
217 | addr->AddressLength = memory32->AddressLength; |
217 | addr->AddressLength = memory32->AddressLength; |
218 | addr->Maximum = addr->Minimum + addr->AddressLength - 1; |
218 | addr->Maximum = addr->Minimum + addr->AddressLength - 1; |
219 | return AE_OK; |
219 | return AE_OK; |
220 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
220 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
221 | fixed_memory32 = &resource->Data.FixedMemory32; |
221 | fixed_memory32 = &resource->Data.FixedMemory32; |
222 | addr->ResourceType = ACPI_MEMORY_RANGE; |
222 | addr->ResourceType = ACPI_MEMORY_RANGE; |
223 | addr->Minimum = fixed_memory32->Address; |
223 | addr->Minimum = fixed_memory32->Address; |
224 | addr->AddressLength = fixed_memory32->AddressLength; |
224 | addr->AddressLength = fixed_memory32->AddressLength; |
225 | addr->Maximum = addr->Minimum + addr->AddressLength - 1; |
225 | addr->Maximum = addr->Minimum + addr->AddressLength - 1; |
226 | return AE_OK; |
226 | return AE_OK; |
227 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
227 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
228 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
228 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
229 | case ACPI_RESOURCE_TYPE_ADDRESS64: |
229 | case ACPI_RESOURCE_TYPE_ADDRESS64: |
230 | status = AcpiResourceToAddress64(resource, addr); |
230 | status = AcpiResourceToAddress64(resource, addr); |
231 | if (ACPI_SUCCESS(status) && |
231 | if (ACPI_SUCCESS(status) && |
232 | (addr->ResourceType == ACPI_MEMORY_RANGE || |
232 | (addr->ResourceType == ACPI_MEMORY_RANGE || |
233 | addr->ResourceType == ACPI_IO_RANGE) && |
233 | addr->ResourceType == ACPI_IO_RANGE) && |
234 | addr->AddressLength > 0) { |
234 | addr->AddressLength > 0) { |
235 | return AE_OK; |
235 | return AE_OK; |
236 | } |
236 | } |
237 | break; |
237 | break; |
238 | } |
238 | } |
239 | return AE_ERROR; |
239 | return AE_ERROR; |
240 | } |
240 | } |
241 | 241 | ||
242 | 242 | ||
243 | static ACPI_STATUS |
243 | static ACPI_STATUS |
244 | count_resource(ACPI_RESOURCE *acpi_res, void *data) |
244 | count_resource(ACPI_RESOURCE *acpi_res, void *data) |
245 | { |
245 | { |
246 | struct pci_root_info *info = data; |
246 | struct pci_root_info *info = data; |
247 | ACPI_RESOURCE_ADDRESS64 addr; |
247 | ACPI_RESOURCE_ADDRESS64 addr; |
248 | ACPI_STATUS status; |
248 | ACPI_STATUS status; |
249 | 249 | ||
250 | status = resource_to_addr(acpi_res, &addr); |
250 | status = resource_to_addr(acpi_res, &addr); |
251 | if (ACPI_SUCCESS(status)) |
251 | if (ACPI_SUCCESS(status)) |
252 | info->res_num++; |
252 | info->res_num++; |
253 | return AE_OK; |
253 | return AE_OK; |
254 | } |
254 | } |
255 | 255 | ||
256 | 256 | ||
257 | static ACPI_STATUS setup_resource(ACPI_RESOURCE *acpi_res, void *data) |
257 | static ACPI_STATUS setup_resource(ACPI_RESOURCE *acpi_res, void *data) |
258 | { |
258 | { |
259 | struct pci_root_info *info = data; |
259 | struct pci_root_info *info = data; |
260 | struct resource *res; |
260 | struct resource *res; |
261 | struct acpi_resource_address64 addr; |
261 | struct acpi_resource_address64 addr; |
262 | ACPI_STATUS status; |
262 | ACPI_STATUS status; |
263 | unsigned long flags; |
263 | unsigned long flags; |
264 | u64 start, end; |
264 | u64 start, end; |
265 | 265 | ||
266 | status = resource_to_addr(acpi_res, &addr); |
266 | status = resource_to_addr(acpi_res, &addr); |
267 | if (!ACPI_SUCCESS(status)) |
267 | if (!ACPI_SUCCESS(status)) |
268 | return AE_OK; |
268 | return AE_OK; |
269 | 269 | ||
270 | if (addr.ResourceType == ACPI_MEMORY_RANGE) |
270 | if (addr.ResourceType == ACPI_MEMORY_RANGE) |
271 | { |
271 | { |
272 | flags = IORESOURCE_MEM; |
272 | flags = IORESOURCE_MEM; |
273 | if (addr.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY) |
273 | if (addr.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY) |
274 | flags |= IORESOURCE_PREFETCH; |
274 | flags |= IORESOURCE_PREFETCH; |
275 | } |
275 | } |
276 | else if (addr.ResourceType == ACPI_IO_RANGE) |
276 | else if (addr.ResourceType == ACPI_IO_RANGE) |
277 | { |
277 | { |
278 | flags = IORESOURCE_IO; |
278 | flags = IORESOURCE_IO; |
279 | } else |
279 | } else |
280 | return AE_OK; |
280 | return AE_OK; |
281 | 281 | ||
282 | start = addr.Minimum + addr.TranslationOffset; |
282 | start = addr.Minimum + addr.TranslationOffset; |
283 | end = addr.Maximum + addr.TranslationOffset; |
283 | end = addr.Maximum + addr.TranslationOffset; |
284 | 284 | ||
285 | res = &info->res[info->res_num]; |
285 | res = &info->res[info->res_num]; |
286 | res->name = info->name; |
286 | res->name = info->name; |
287 | res->flags = flags; |
287 | res->flags = flags; |
288 | res->start = start; |
288 | res->start = start; |
289 | res->end = end; |
289 | res->end = end; |
290 | res->child = NULL; |
290 | res->child = NULL; |
291 | 291 | ||
292 | if (!pci_use_crs) { |
292 | if (!pci_use_crs) { |
293 | printk("host bridge window %pR (ignored)\n", res); |
293 | printk("host bridge window %pR (ignored)\n", res); |
294 | return AE_OK; |
294 | return AE_OK; |
295 | } |
295 | } |
296 | 296 | ||
297 | info->res_num++; |
297 | info->res_num++; |
298 | if (addr.TranslationOffset) |
298 | if (addr.TranslationOffset) |
299 | dev_info(NULL, "host bridge window %pR " |
299 | dev_info(NULL, "host bridge window %pR " |
300 | "(PCI address [%#llx-%#llx])\n", |
300 | "(PCI address [%#llx-%#llx])\n", |
301 | res, res->start - addr.TranslationOffset, |
301 | res, res->start - addr.TranslationOffset, |
302 | res->end - addr.TranslationOffset); |
302 | res->end - addr.TranslationOffset); |
303 | else |
303 | else |
304 | dev_info(NULL, |
304 | dev_info(NULL, |
305 | "host bridge window %pR\n", res); |
305 | "host bridge window %pR\n", res); |
306 | 306 | ||
307 | return AE_OK; |
307 | return AE_OK; |
308 | } |
308 | } |
309 | 309 | ||
310 | 310 | ||
311 | 311 | ||
312 | static void |
312 | static void |
313 | get_current_resources(struct acpi_device *device, int busnum, |
313 | get_current_resources(struct acpi_device *device, int busnum, |
314 | int domain, struct pci_bus *bus) |
314 | int domain, struct pci_bus *bus) |
315 | { |
315 | { |
316 | struct pci_root_info info; |
316 | struct pci_root_info info; |
317 | size_t size; |
317 | size_t size; |
318 | 318 | ||
319 | char buf[64]; |
319 | char buf[64]; |
320 | 320 | ||
321 | // if (pci_use_crs) |
321 | // if (pci_use_crs) |
322 | // pci_bus_remove_resources(bus); |
322 | // pci_bus_remove_resources(bus); |
323 | 323 | ||
324 | info.bridge = device; |
324 | info.bridge = device; |
325 | info.bus = bus; |
325 | info.bus = bus; |
326 | info.res_num = 0; |
326 | info.res_num = 0; |
327 | AcpiWalkResources(device->handle, METHOD_NAME__CRS, count_resource, |
327 | AcpiWalkResources(device->handle, METHOD_NAME__CRS, count_resource, |
328 | &info); |
328 | &info); |
329 | if (!info.res_num) |
329 | if (!info.res_num) |
330 | return; |
330 | return; |
331 | 331 | ||
332 | size = sizeof(*info.res) * info.res_num; |
332 | size = sizeof(*info.res) * info.res_num; |
333 | info.res = kmalloc(size, GFP_KERNEL); |
333 | info.res = kmalloc(size, GFP_KERNEL); |
334 | if (!info.res) |
334 | if (!info.res) |
335 | goto res_alloc_fail; |
335 | goto res_alloc_fail; |
336 | 336 | ||
337 | sprintf(buf,"PCI Bus %04x:%02x", domain, busnum); |
337 | sprintf(buf,"PCI Bus %04x:%02x", domain, busnum); |
338 | 338 | ||
339 | info.name = strdup(buf); |
339 | info.name = strdup(buf); |
340 | 340 | ||
341 | if (!info.name) |
341 | if (!info.name) |
342 | goto name_alloc_fail; |
342 | goto name_alloc_fail; |
343 | 343 | ||
344 | info.res_num = 0; |
344 | info.res_num = 0; |
345 | AcpiWalkResources(device->handle, METHOD_NAME__CRS, setup_resource, |
345 | AcpiWalkResources(device->handle, METHOD_NAME__CRS, setup_resource, |
346 | &info); |
346 | &info); |
347 | 347 | ||
348 | return; |
348 | return; |
349 | 349 | ||
350 | name_alloc_fail: |
350 | name_alloc_fail: |
351 | kfree(info.res); |
351 | kfree(info.res); |
352 | res_alloc_fail: |
352 | res_alloc_fail: |
353 | return; |
353 | return; |
354 | } |
354 | } |
355 | 355 | ||
356 | 356 | ||
357 | struct pci_ops pci_root_ops = { |
357 | struct pci_ops pci_root_ops = { |
358 | .read = NULL, |
358 | .read = NULL, |
359 | .write = NULL, |
359 | .write = NULL, |
360 | }; |
360 | }; |
361 | 361 | ||
362 | 362 | ||
363 | struct pci_bus* pci_acpi_scan_root(struct acpi_pci_root *root) |
363 | struct pci_bus* pci_acpi_scan_root(struct acpi_pci_root *root) |
364 | { |
364 | { |
365 | struct acpi_device *device = root->device; |
365 | struct acpi_device *device = root->device; |
366 | int domain = root->segment; |
366 | int domain = root->segment; |
367 | int busnum = root->secondary.start; |
367 | int busnum = root->secondary.start; |
368 | struct pci_bus *bus; |
368 | struct pci_bus *bus; |
369 | struct pci_sysdata *sd; |
369 | struct pci_sysdata *sd; |
370 | int node = 0; |
370 | int node = 0; |
371 | 371 | ||
372 | if (domain ) { |
372 | if (domain ) { |
373 | printk(KERN_WARNING "pci_bus %04x:%02x: " |
373 | printk(KERN_WARNING "pci_bus %04x:%02x: " |
374 | "ignored (multiple domains not supported)\n", |
374 | "ignored (multiple domains not supported)\n", |
375 | domain, busnum); |
375 | domain, busnum); |
376 | return NULL; |
376 | return NULL; |
377 | } |
377 | } |
378 | 378 | ||
379 | node = -1; |
379 | node = -1; |
380 | /* Allocate per-root-bus (not per bus) arch-specific data. |
380 | /* Allocate per-root-bus (not per bus) arch-specific data. |
381 | * TODO: leak; this memory is never freed. |
381 | * TODO: leak; this memory is never freed. |
382 | * It's arguable whether it's worth the trouble to care. |
382 | * It's arguable whether it's worth the trouble to care. |
383 | */ |
383 | */ |
384 | sd = kzalloc(sizeof(*sd), GFP_KERNEL); |
384 | sd = kzalloc(sizeof(*sd), GFP_KERNEL); |
385 | if (!sd) { |
385 | if (!sd) { |
386 | printk(KERN_WARNING "pci_bus %04x:%02x: " |
386 | printk(KERN_WARNING "pci_bus %04x:%02x: " |
387 | "ignored (out of memory)\n", domain, busnum); |
387 | "ignored (out of memory)\n", domain, busnum); |
388 | return NULL; |
388 | return NULL; |
389 | } |
389 | } |
390 | 390 | ||
391 | sd->domain = domain; |
391 | sd->domain = domain; |
392 | sd->node = node; |
392 | sd->node = node; |
393 | /* |
393 | /* |
394 | * Maybe the desired pci bus has been already scanned. In such case |
394 | * Maybe the desired pci bus has been already scanned. In such case |
395 | * it is unnecessary to scan the pci bus with the given domain,busnum. |
395 | * it is unnecessary to scan the pci bus with the given domain,busnum. |
396 | */ |
396 | */ |
397 | bus = pci_find_bus(domain, busnum); |
397 | bus = pci_find_bus(domain, busnum); |
398 | if (bus) { |
398 | if (bus) { |
399 | /* |
399 | /* |
400 | * If the desired bus exits, the content of bus->sysdata will |
400 | * If the desired bus exits, the content of bus->sysdata will |
401 | * be replaced by sd. |
401 | * be replaced by sd. |
402 | */ |
402 | */ |
403 | memcpy(bus->sysdata, sd, sizeof(*sd)); |
403 | memcpy(bus->sysdata, sd, sizeof(*sd)); |
404 | kfree(sd); |
404 | kfree(sd); |
405 | } else { |
405 | } else { |
406 | bus = pci_create_bus(busnum, &pci_root_ops, sd); |
406 | bus = pci_create_bus(busnum, &pci_root_ops, sd); |
407 | if (bus) { |
407 | if (bus) { |
408 | get_current_resources(device, busnum, domain, bus); |
408 | get_current_resources(device, busnum, domain, bus); |
409 | bus->subordinate = pci_scan_child_bus(bus); |
409 | bus->subordinate = pci_scan_child_bus(bus); |
410 | } |
410 | } |
411 | } |
411 | } |
412 | 412 | ||
413 | if (!bus) |
413 | if (!bus) |
414 | kfree(sd); |
414 | kfree(sd); |
415 | 415 | ||
416 | if (bus && node != -1) { |
416 | if (bus && node != -1) { |
417 | printk("on NUMA node %d\n", node); |
417 | printk("on NUMA node %d\n", node); |
418 | } |
418 | } |
419 | 419 | ||
420 | return bus; |
420 | return bus; |
421 | } |
421 | } |
422 | 422 | ||
423 | 423 | ||
424 | 424 | ||
425 | static int acpi_pci_root_add(struct acpi_device *device) |
425 | static int acpi_pci_root_add(struct acpi_device *device) |
426 | { |
426 | { |
427 | unsigned long long segment, bus; |
427 | unsigned long long segment, bus; |
428 | ACPI_STATUS status; |
428 | ACPI_STATUS status; |
429 | int result; |
429 | int result; |
430 | struct acpi_pci_root *root; |
430 | struct acpi_pci_root *root; |
431 | ACPI_HANDLE handle; |
431 | ACPI_HANDLE handle; |
432 | struct acpi_device *child; |
432 | struct acpi_device *child; |
433 | u32 flags, base_flags; |
433 | u32 flags, base_flags; |
434 | 434 | ||
435 | root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); |
435 | root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); |
436 | if (!root) |
436 | if (!root) |
437 | return -ENOMEM; |
437 | return -ENOMEM; |
438 | 438 | ||
439 | segment = 0; |
439 | segment = 0; |
440 | status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL, |
440 | status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL, |
441 | &segment); |
441 | &segment); |
442 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
442 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
443 | printk(KERN_ERR PREFIX "can't evaluate _SEG\n"); |
443 | printk(KERN_ERR PREFIX "can't evaluate _SEG\n"); |
444 | result = -ENODEV; |
444 | result = -ENODEV; |
445 | goto end; |
445 | goto end; |
446 | } |
446 | } |
447 | 447 | ||
448 | /* Check _CRS first, then _BBN. If no _BBN, default to zero. */ |
448 | /* Check _CRS first, then _BBN. If no _BBN, default to zero. */ |
449 | root->secondary.flags = IORESOURCE_BUS; |
449 | root->secondary.flags = IORESOURCE_BUS; |
450 | status = try_get_root_bridge_busnr(device->handle, &root->secondary); |
450 | status = try_get_root_bridge_busnr(device->handle, &root->secondary); |
451 | if (ACPI_FAILURE(status)) |
451 | if (ACPI_FAILURE(status)) |
452 | { |
452 | { |
453 | /* |
453 | /* |
454 | * We need both the start and end of the downstream bus range |
454 | * We need both the start and end of the downstream bus range |
455 | * to interpret _CBA (MMCONFIG base address), so it really is |
455 | * to interpret _CBA (MMCONFIG base address), so it really is |
456 | * supposed to be in _CRS. If we don't find it there, all we |
456 | * supposed to be in _CRS. If we don't find it there, all we |
457 | * can do is assume [_BBN-0xFF] or [0-0xFF]. |
457 | * can do is assume [_BBN-0xFF] or [0-0xFF]. |
458 | */ |
458 | */ |
459 | root->secondary.end = 0xFF; |
459 | root->secondary.end = 0xFF; |
460 | printk(KERN_WARNING PREFIX |
460 | printk(KERN_WARNING PREFIX |
461 | "no secondary bus range in _CRS\n"); |
461 | "no secondary bus range in _CRS\n"); |
462 | status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, &bus); |
462 | status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, &bus); |
463 | if (ACPI_SUCCESS(status)) |
463 | if (ACPI_SUCCESS(status)) |
464 | root->secondary.start = bus; |
464 | root->secondary.start = bus; |
465 | else if (status == AE_NOT_FOUND) |
465 | else if (status == AE_NOT_FOUND) |
466 | root->secondary.start = 0; |
466 | root->secondary.start = 0; |
467 | else { |
467 | else { |
468 | printk(KERN_ERR PREFIX "can't evaluate _BBN\n"); |
468 | printk(KERN_ERR PREFIX "can't evaluate _BBN\n"); |
469 | result = -ENODEV; |
469 | result = -ENODEV; |
470 | goto end; |
470 | goto end; |
471 | } |
471 | } |
472 | } |
472 | } |
473 | 473 | ||
474 | INIT_LIST_HEAD(&root->node); |
474 | INIT_LIST_HEAD(&root->node); |
475 | root->device = device; |
475 | root->device = device; |
476 | root->segment = segment & 0xFFFF; |
476 | root->segment = segment & 0xFFFF; |
477 | strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); |
477 | strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); |
478 | strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); |
478 | strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); |
479 | device->driver_data = root; |
479 | device->driver_data = root; |
480 | 480 | ||
481 | /* |
481 | /* |
482 | * All supported architectures that use ACPI have support for |
482 | * All supported architectures that use ACPI have support for |
483 | * PCI domains, so we indicate this in _OSC support capabilities. |
483 | * PCI domains, so we indicate this in _OSC support capabilities. |
484 | */ |
484 | */ |
485 | // flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; |
485 | // flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; |
486 | // acpi_pci_osc_support(root, flags); |
486 | // acpi_pci_osc_support(root, flags); |
487 | 487 | ||
488 | /* |
488 | /* |
489 | * TBD: Need PCI interface for enumeration/configuration of roots. |
489 | * TBD: Need PCI interface for enumeration/configuration of roots. |
490 | */ |
490 | */ |
491 | 491 | ||
492 | /* TBD: Locking */ |
492 | /* TBD: Locking */ |
493 | list_add_tail(&root->node, &acpi_pci_roots); |
493 | list_add_tail(&root->node, &acpi_pci_roots); |
494 | 494 | ||
495 | printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n", |
495 | printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n", |
496 | acpi_device_name(device), acpi_device_bid(device), |
496 | acpi_device_name(device), acpi_device_bid(device), |
497 | root->segment, &root->secondary); |
497 | root->segment, &root->secondary); |
498 | 498 | ||
499 | /* |
499 | /* |
500 | * Scan the Root Bridge |
500 | * Scan the Root Bridge |
501 | * -------------------- |
501 | * -------------------- |
502 | * Must do this prior to any attempt to bind the root device, as the |
502 | * Must do this prior to any attempt to bind the root device, as the |
503 | * PCI namespace does not get created until this call is made (and |
503 | * PCI namespace does not get created until this call is made (and |
504 | * thus the root bridge's pci_dev does not exist). |
504 | * thus the root bridge's pci_dev does not exist). |
505 | */ |
505 | */ |
506 | 506 | ||
507 | root->bus = pci_acpi_scan_root(root); |
507 | root->bus = pci_acpi_scan_root(root); |
508 | if (!root->bus) { |
508 | if (!root->bus) { |
509 | printk(KERN_ERR PREFIX |
509 | printk(KERN_ERR PREFIX |
510 | "Bus %04x:%02x not present in PCI namespace\n", |
510 | "Bus %04x:%02x not present in PCI namespace\n", |
511 | root->segment, (unsigned int)root->secondary.start); |
511 | root->segment, (unsigned int)root->secondary.start); |
512 | result = -ENODEV; |
512 | result = -ENODEV; |
513 | goto end; |
513 | goto end; |
514 | } |
514 | } |
515 | 515 | ||
516 | /* |
516 | /* |
517 | * Attach ACPI-PCI Context |
517 | * Attach ACPI-PCI Context |
518 | * ----------------------- |
518 | * ----------------------- |
519 | * Thus binding the ACPI and PCI devices. |
519 | * Thus binding the ACPI and PCI devices. |
520 | */ |
520 | */ |
521 | result = acpi_pci_bind_root(device); |
521 | result = acpi_pci_bind_root(device); |
522 | if (result) |
522 | if (result) |
523 | goto end; |
523 | goto end; |
524 | 524 | ||
525 | /* |
525 | /* |
526 | * PCI Routing Table |
526 | * PCI Routing Table |
527 | * ----------------- |
527 | * ----------------- |
528 | * Evaluate and parse _PRT, if exists. |
528 | * Evaluate and parse _PRT, if exists. |
529 | */ |
529 | */ |
530 | status = AcpiGetHandle(device->handle, METHOD_NAME__PRT, &handle); |
530 | status = AcpiGetHandle(device->handle, METHOD_NAME__PRT, &handle); |
531 | if (ACPI_SUCCESS(status)) |
531 | if (ACPI_SUCCESS(status)) |
532 | result = acpi_pci_irq_add_prt(device->handle, root->bus); |
532 | result = acpi_pci_irq_add_prt(device->handle, root->bus); |
533 | 533 | ||
534 | /* |
534 | /* |
535 | * Scan and bind all _ADR-Based Devices |
535 | * Scan and bind all _ADR-Based Devices |
536 | */ |
536 | */ |
537 | list_for_each_entry(child, &device->children, node) |
537 | list_for_each_entry(child, &device->children, node) |
538 | acpi_pci_bridge_scan(child); |
538 | acpi_pci_bridge_scan(child); |
539 | 539 | ||
540 | return 0; |
540 | return 0; |
541 | 541 | ||
542 | end: |
542 | end: |
543 | if (!list_empty(&root->node)) |
543 | if (!list_empty(&root->node)) |
544 | list_del(&root->node); |
544 | list_del(&root->node); |
545 | kfree(root); |
545 | kfree(root); |
546 | return result; |
546 | return result; |
547 | } |
547 | } |
548 | 548 | ||
549 | 549 | ||
550 | static const struct acpi_device_ids root_device_ids[] = |
550 | static const struct acpi_device_ids root_device_ids[] = |
551 | { |
551 | { |
552 | {"PNP0A03", 0}, |
552 | {"PNP0A03", 0}, |
553 | {"", 0}, |
553 | {"", 0}, |
554 | }; |
554 | }; |
555 | 555 | ||
556 | void acpi_init_pci(struct acpi_device *device) |
556 | void acpi_init_pci(struct acpi_device *device) |
557 | { |
557 | { |
558 | struct acpi_device *child; |
558 | struct acpi_device *child; |
559 | 559 | ||
560 | if ( !acpi_match_device_ids(device, root_device_ids) ) |
560 | if ( !acpi_match_device_ids(device, root_device_ids) ) |
561 | { |
561 | { |
562 | dbgprintf(PREFIX "PCI root %s\n", device->pnp.bus_id); |
562 | dbgprintf(PREFIX "PCI root %s\n", device->pnp.bus_id); |
563 | acpi_pci_root_add(device); |
563 | acpi_pci_root_add(device); |
564 | }; |
564 | }; |
565 | 565 | ||
566 | list_for_each_entry(child, &device->children, node) |
566 | list_for_each_entry(child, &device->children, node) |
567 | { |
567 | { |
568 | acpi_init_pci(child); |
568 | acpi_init_pci(child); |
569 | }; |
569 | }; |
570 | 570 | ||
571 | }; |
571 | }; |
572 | 572 | ||
573 | uint32_t drvEntry(int action, char *cmdline) |
573 | uint32_t drvEntry(int action, char *cmdline) |
574 | { |
574 | { |
575 | uint32_t retval; |
575 | uint32_t retval; |
576 | ACPI_STATUS status; |
576 | ACPI_STATUS status; |
577 | int i; |
577 | int i; |
578 | 578 | ||
579 | if(action != 1) |
579 | if(action != 1) |
580 | return 0; |
580 | return 0; |
581 | 581 | ||
582 | status = AcpiInitializeSubsystem(); |
582 | status = AcpiInitializeSubsystem(); |
583 | if (status != AE_OK) { |
583 | if (status != AE_OK) { |
584 | printf("AcpiInitializeSubsystem failed (%s)\n", |
584 | printf("AcpiInitializeSubsystem failed (%s)\n", |
585 | AcpiFormatException(status)); |
585 | AcpiFormatException(status)); |
586 | goto err; |
586 | goto err; |
587 | } |
587 | } |
588 | 588 | ||
589 | status = AcpiInitializeTables (NULL, 16, FALSE); |
589 | status = AcpiInitializeTables (NULL, 16, FALSE); |
590 | if (status != AE_OK) { |
590 | if (status != AE_OK) { |
591 | printf("AcpiInitializeTables failed (%s)\n", |
591 | printf("AcpiInitializeTables failed (%s)\n", |
592 | AcpiFormatException(status)); |
592 | AcpiFormatException(status)); |
593 | goto err; |
593 | goto err; |
594 | } |
594 | } |
595 | 595 | ||
596 | status = AcpiLoadTables(); |
596 | status = AcpiLoadTables(); |
597 | if (status != AE_OK) { |
597 | if (status != AE_OK) { |
598 | printf("AcpiLoadTables failed (%s)\n", |
598 | printf("AcpiLoadTables failed (%s)\n", |
599 | AcpiFormatException(status)); |
599 | AcpiFormatException(status)); |
600 | goto err; |
600 | goto err; |
601 | } |
601 | } |
602 | 602 | ||
603 | // u32_t mode = ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE; |
603 | // u32_t mode = ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE; |
604 | 604 | ||
605 | status = AcpiEnableSubsystem(ACPI_NO_HANDLER_INIT | ACPI_NO_HARDWARE_INIT); |
605 | status = AcpiEnableSubsystem(ACPI_NO_HANDLER_INIT | ACPI_NO_HARDWARE_INIT); |
606 | if (status != AE_OK) { |
606 | if (status != AE_OK) { |
607 | dbgprintf("AcpiEnableSubsystem failed (%s)\n", |
607 | dbgprintf("AcpiEnableSubsystem failed (%s)\n", |
608 | AcpiFormatException(status)); |
608 | AcpiFormatException(status)); |
609 | goto err; |
609 | goto err; |
610 | } |
610 | } |
611 | 611 | ||
612 | status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION); |
612 | status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION); |
613 | if (ACPI_FAILURE (status)) |
613 | if (ACPI_FAILURE (status)) |
614 | { |
614 | { |
615 | dbgprintf("AcpiInitializeObjects failed (%s)\n", |
615 | dbgprintf("AcpiInitializeObjects failed (%s)\n", |
616 | AcpiFormatException(status)); |
616 | AcpiFormatException(status)); |
617 | goto err; |
617 | goto err; |
618 | } |
618 | } |
619 | 619 | ||
620 | set_pic_mode(IO_APIC); |
620 | set_pic_mode(IO_APIC); |
621 | acpi_scan(); |
621 | acpi_scan(); |
622 | acpi_init_pci(acpi_root); |
622 | acpi_init_pci(acpi_root); |
623 | print_pci_irqs(); |
623 | print_pci_irqs(); |
624 | create_dm_list(); |
624 | create_dm_list(); |
625 | print_dm_list(); |
625 | print_dm_list(); |
626 | 626 | ||
627 | write_device_dat("/RD/1/DRIVERS/DEVICES.DAT"); |
627 | write_device_dat("/SYS/DRIVERS/DEVICES.DAT"); |
628 | 628 | ||
629 | err: |
629 | err: |
630 | return 0; |
630 | return 0; |
631 | }; |
631 | }; |
632 | 632 | ||
633 | char* strdup(const char *str) |
633 | char* strdup(const char *str) |
634 | { |
634 | { |
635 | size_t len = strlen (str) + 1; |
635 | size_t len = strlen (str) + 1; |
636 | char *copy = malloc(len); |
636 | char *copy = malloc(len); |
637 | if (copy) |
637 | if (copy) |
638 | { |
638 | { |
639 | memcpy (copy, str, len); |
639 | memcpy (copy, str, len); |
640 | } |
640 | } |
641 | return copy; |
641 | return copy; |
642 | } |
642 | } |
643 | 643 | ||
644 | 644 | ||
645 | static void dm_add_pci_bus(struct pci_bus *bus) |
645 | static void dm_add_pci_bus(struct pci_bus *bus) |
646 | { |
646 | { |
647 | struct pci_bus *tbus; |
647 | struct pci_bus *tbus; |
648 | struct pci_dev *dev; |
648 | struct pci_dev *dev; |
649 | dmdev_t *dmdev; |
649 | dmdev_t *dmdev; |
650 | 650 | ||
651 | dmdev = (dmdev_t*)kzalloc(sizeof(dmdev_t),GFP_KERNEL); |
651 | dmdev = (dmdev_t*)kzalloc(sizeof(dmdev_t),GFP_KERNEL); |
652 | 652 | ||
653 | // INIT_LIST_HEAD(&dmdev->list); |
653 | // INIT_LIST_HEAD(&dmdev->list); |
654 | // dmdev->type = 1; |
654 | // dmdev->type = 1; |
655 | // dmdev->acpi_dev = bus->self->acpi_dev; |
655 | // dmdev->acpi_dev = bus->self->acpi_dev; |
656 | // dmdev->pci_dev = bus->self; |
656 | // dmdev->pci_dev = bus->self; |
657 | // list_add_tail(&dmdev->list, &dmdev_tree); |
657 | // list_add_tail(&dmdev->list, &dmdev_tree); |
658 | 658 | ||
659 | list_for_each_entry(dev, &bus->devices, bus_list) |
659 | list_for_each_entry(dev, &bus->devices, bus_list) |
660 | { |
660 | { |
661 | dmdev = (dmdev_t*)kzalloc(sizeof(dmdev_t),GFP_KERNEL); |
661 | dmdev = (dmdev_t*)kzalloc(sizeof(dmdev_t),GFP_KERNEL); |
662 | 662 | ||
663 | INIT_LIST_HEAD(&dmdev->list); |
663 | INIT_LIST_HEAD(&dmdev->list); |
664 | dmdev->type = 1; |
664 | dmdev->type = 1; |
665 | dmdev->acpi_dev = dev->acpi_dev; |
665 | dmdev->acpi_dev = dev->acpi_dev; |
666 | dmdev->pci_dev = dev; |
666 | dmdev->pci_dev = dev; |
667 | list_add_tail(&dmdev->list, &dmdev_tree); |
667 | list_add_tail(&dmdev->list, &dmdev_tree); |
668 | }; |
668 | }; |
669 | 669 | ||
670 | list_for_each_entry(tbus, &bus->children, node) |
670 | list_for_each_entry(tbus, &bus->children, node) |
671 | { |
671 | { |
672 | dm_add_pci_bus(tbus); |
672 | dm_add_pci_bus(tbus); |
673 | }; |
673 | }; |
674 | 674 | ||
675 | }; |
675 | }; |
676 | 676 | ||
677 | static ACPI_STATUS |
677 | static ACPI_STATUS |
678 | count_dev_resources(ACPI_RESOURCE *acpi_res, void *data) |
678 | count_dev_resources(ACPI_RESOURCE *acpi_res, void *data) |
679 | { |
679 | { |
680 | (*(int*)data)++; |
680 | (*(int*)data)++; |
681 | return AE_OK; |
681 | return AE_OK; |
682 | } |
682 | } |
683 | 683 | ||
684 | static void dm_add_acpi(struct acpi_device *device) |
684 | static void dm_add_acpi(struct acpi_device *device) |
685 | { |
685 | { |
686 | struct acpi_device *child; |
686 | struct acpi_device *child; |
687 | ACPI_DEVICE_INFO *info = NULL; |
687 | ACPI_DEVICE_INFO *info = NULL; |
688 | ACPI_STATUS status; |
688 | ACPI_STATUS status; |
689 | 689 | ||
690 | dmdev_t *dmdev; |
690 | dmdev_t *dmdev; |
691 | uint32_t res_num = 0; |
691 | uint32_t res_num = 0; |
692 | 692 | ||
693 | status = AcpiGetObjectInfo(device->handle, &info); |
693 | status = AcpiGetObjectInfo(device->handle, &info); |
694 | 694 | ||
695 | if ( (status == AE_OK) && (info->Valid & ACPI_VALID_HID)) |
695 | if ( (status == AE_OK) && (info->Valid & ACPI_VALID_HID)) |
696 | { |
696 | { |
697 | if( strcmp(info->HardwareId.String,"PNP0C0F") == 0) |
697 | if( strcmp(info->HardwareId.String,"PNP0C0F") == 0) |
698 | { |
698 | { |
699 | kfree(info); |
699 | kfree(info); |
700 | return; |
700 | return; |
701 | }; |
701 | }; |
702 | }; |
702 | }; |
703 | 703 | ||
704 | kfree(info); |
704 | kfree(info); |
705 | 705 | ||
706 | if(device->pci_dev == NULL) |
706 | if(device->pci_dev == NULL) |
707 | { |
707 | { |
708 | AcpiWalkResources(device->handle, METHOD_NAME__CRS, |
708 | AcpiWalkResources(device->handle, METHOD_NAME__CRS, |
709 | count_dev_resources, &res_num); |
709 | count_dev_resources, &res_num); |
710 | 710 | ||
711 | if(res_num != 0) |
711 | if(res_num != 0) |
712 | { |
712 | { |
713 | dmdev = (dmdev_t*)kzalloc(sizeof(dmdev_t),GFP_KERNEL); |
713 | dmdev = (dmdev_t*)kzalloc(sizeof(dmdev_t),GFP_KERNEL); |
714 | 714 | ||
715 | INIT_LIST_HEAD(&dmdev->list); |
715 | INIT_LIST_HEAD(&dmdev->list); |
716 | dmdev->type = 0; |
716 | dmdev->type = 0; |
717 | dmdev->acpi_dev = device; |
717 | dmdev->acpi_dev = device; |
718 | dmdev->pci_dev = NULL; |
718 | dmdev->pci_dev = NULL; |
719 | list_add_tail(&dmdev->list, &dmdev_tree); |
719 | list_add_tail(&dmdev->list, &dmdev_tree); |
720 | }; |
720 | }; |
721 | }; |
721 | }; |
722 | list_for_each_entry(child, &device->children, node) |
722 | list_for_each_entry(child, &device->children, node) |
723 | { |
723 | { |
724 | dm_add_acpi(child); |
724 | dm_add_acpi(child); |
725 | }; |
725 | }; |
726 | }; |
726 | }; |
727 | 727 | ||
728 | static void create_dm_list() |
728 | static void create_dm_list() |
729 | { |
729 | { |
730 | struct acpi_pci_root *root; |
730 | struct acpi_pci_root *root; |
731 | 731 | ||
732 | list_for_each_entry(root, &acpi_pci_roots, node) |
732 | list_for_each_entry(root, &acpi_pci_roots, node) |
733 | { |
733 | { |
734 | struct pci_bus *pbus, *tbus; |
734 | struct pci_bus *pbus, *tbus; |
735 | struct pci_dev *dev; |
735 | struct pci_dev *dev; |
736 | 736 | ||
737 | pbus = root->bus; |
737 | pbus = root->bus; |
738 | 738 | ||
739 | dm_add_pci_bus(pbus); |
739 | dm_add_pci_bus(pbus); |
740 | }; |
740 | }; |
741 | 741 | ||
742 | dm_add_acpi(acpi_root); |
742 | dm_add_acpi(acpi_root); |
743 | }; |
743 | }; |
744 | 744 | ||
745 | static void print_pci_resource(struct resource *res) |
745 | static void print_pci_resource(struct resource *res) |
746 | { |
746 | { |
747 | if(res->flags !=0 ) |
747 | if(res->flags !=0 ) |
748 | { |
748 | { |
749 | if(res->flags & IORESOURCE_IO) |
749 | if(res->flags & IORESOURCE_IO) |
750 | dbgprintf(" IO range "); |
750 | dbgprintf(" IO range "); |
751 | else if(res->flags & IORESOURCE_MEM) |
751 | else if(res->flags & IORESOURCE_MEM) |
752 | dbgprintf(" MMIO range "); |
752 | dbgprintf(" MMIO range "); |
753 | dbgprintf("%x - %x\n", res->start, res->end); |
753 | dbgprintf("%x - %x\n", res->start, res->end); |
754 | }; |
754 | }; |
755 | }; |
755 | }; |
756 | 756 | ||
757 | static ACPI_STATUS |
757 | static ACPI_STATUS |
758 | print_acpi_resource(ACPI_RESOURCE *acpi_res, void *data) |
758 | print_acpi_resource(ACPI_RESOURCE *acpi_res, void *data) |
759 | { |
759 | { |
760 | ACPI_RESOURCE_ADDRESS64 addr; |
760 | ACPI_RESOURCE_ADDRESS64 addr; |
761 | ACPI_STATUS status; |
761 | ACPI_STATUS status; |
762 | int i; |
762 | int i; |
763 | 763 | ||
764 | switch (acpi_res->Type) |
764 | switch (acpi_res->Type) |
765 | { |
765 | { |
766 | case ACPI_RESOURCE_TYPE_IRQ: |
766 | case ACPI_RESOURCE_TYPE_IRQ: |
767 | { |
767 | { |
768 | ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*)&acpi_res->Data; |
768 | ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*)&acpi_res->Data; |
769 | dbgprintf(" IRQ %d\n", irq_data->Interrupts[0]); |
769 | dbgprintf(" IRQ %d\n", irq_data->Interrupts[0]); |
770 | }; |
770 | }; |
771 | break; |
771 | break; |
772 | 772 | ||
773 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
773 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
774 | { |
774 | { |
775 | ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*)&acpi_res->Data; |
775 | ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*)&acpi_res->Data; |
776 | dbgprintf(" IRQ %d\n", irq_data->Interrupts[0]); |
776 | dbgprintf(" IRQ %d\n", irq_data->Interrupts[0]); |
777 | }; |
777 | }; |
778 | break; |
778 | break; |
779 | 779 | ||
780 | case ACPI_RESOURCE_TYPE_DMA: |
780 | case ACPI_RESOURCE_TYPE_DMA: |
781 | { |
781 | { |
782 | ACPI_RESOURCE_DMA *dma_data = (ACPI_RESOURCE_DMA*) &acpi_res->Data; |
782 | ACPI_RESOURCE_DMA *dma_data = (ACPI_RESOURCE_DMA*) &acpi_res->Data; |
783 | for(i=0; i < dma_data->ChannelCount; i++) |
783 | for(i=0; i < dma_data->ChannelCount; i++) |
784 | { |
784 | { |
785 | dbgprintf(" DMA %s channel %d\n", |
785 | dbgprintf(" DMA %s channel %d\n", |
786 | dma_data->Type == ACPI_TYPE_A ? "Type A": |
786 | dma_data->Type == ACPI_TYPE_A ? "Type A": |
787 | dma_data->Type == ACPI_TYPE_B ? "Type B" : |
787 | dma_data->Type == ACPI_TYPE_B ? "Type B" : |
788 | dma_data->Type == ACPI_TYPE_F ? "Type F" : "", |
788 | dma_data->Type == ACPI_TYPE_F ? "Type F" : "", |
789 | dma_data->Channels[i]); |
789 | dma_data->Channels[i]); |
790 | } |
790 | } |
791 | }; |
791 | }; |
792 | break; |
792 | break; |
793 | 793 | ||
794 | case ACPI_RESOURCE_TYPE_IO: |
794 | case ACPI_RESOURCE_TYPE_IO: |
795 | { |
795 | { |
796 | ACPI_RESOURCE_IO *io_data = (ACPI_RESOURCE_IO*) &acpi_res->Data; |
796 | ACPI_RESOURCE_IO *io_data = (ACPI_RESOURCE_IO*) &acpi_res->Data; |
797 | 797 | ||
798 | dbgprintf(" IO range 0%x-0%x\n",io_data->Minimum, |
798 | dbgprintf(" IO range 0%x-0%x\n",io_data->Minimum, |
799 | io_data->Minimum+io_data->AddressLength-1); |
799 | io_data->Minimum+io_data->AddressLength-1); |
800 | } |
800 | } |
801 | break; |
801 | break; |
802 | 802 | ||
803 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
803 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
804 | { |
804 | { |
805 | ACPI_RESOURCE_FIXED_IO *io_data = (ACPI_RESOURCE_FIXED_IO*) &acpi_res->Data; |
805 | ACPI_RESOURCE_FIXED_IO *io_data = (ACPI_RESOURCE_FIXED_IO*) &acpi_res->Data; |
806 | dbgprintf(" Fixed IO range 0%x-0%x\n",io_data->Address, |
806 | dbgprintf(" Fixed IO range 0%x-0%x\n",io_data->Address, |
807 | io_data->Address+io_data->AddressLength-1); |
807 | io_data->Address+io_data->AddressLength-1); |
808 | }; |
808 | }; |
809 | break; |
809 | break; |
810 | 810 | ||
811 | case ACPI_RESOURCE_TYPE_MEMORY24: |
811 | case ACPI_RESOURCE_TYPE_MEMORY24: |
812 | case ACPI_RESOURCE_TYPE_MEMORY32: |
812 | case ACPI_RESOURCE_TYPE_MEMORY32: |
813 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
813 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
814 | { |
814 | { |
815 | ACPI_RESOURCE_ADDRESS64 addr64; |
815 | ACPI_RESOURCE_ADDRESS64 addr64; |
816 | resource_to_addr(acpi_res, &addr64); |
816 | resource_to_addr(acpi_res, &addr64); |
817 | dbgprintf(" Memory range 0%x-0%x\n", |
817 | dbgprintf(" Memory range 0%x-0%x\n", |
818 | (uint32_t)addr64.Minimum, (uint32_t)addr64.Maximum); |
818 | (uint32_t)addr64.Minimum, (uint32_t)addr64.Maximum); |
819 | } |
819 | } |
820 | break; |
820 | break; |
821 | 821 | ||
822 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
822 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
823 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
823 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
824 | case ACPI_RESOURCE_TYPE_ADDRESS64: |
824 | case ACPI_RESOURCE_TYPE_ADDRESS64: |
825 | { |
825 | { |
826 | ACPI_RESOURCE_ADDRESS64 addr64; |
826 | ACPI_RESOURCE_ADDRESS64 addr64; |
827 | ACPI_STATUS status; |
827 | ACPI_STATUS status; |
828 | 828 | ||
829 | status = AcpiResourceToAddress64(acpi_res, &addr64); |
829 | status = AcpiResourceToAddress64(acpi_res, &addr64); |
830 | if (ACPI_SUCCESS(status)) |
830 | if (ACPI_SUCCESS(status)) |
831 | { |
831 | { |
832 | dbgprintf(" Address range 0%x-0%x\n", |
832 | dbgprintf(" Address range 0%x-0%x\n", |
833 | (uint32_t)addr64.Minimum, (uint32_t)addr64.Maximum); |
833 | (uint32_t)addr64.Minimum, (uint32_t)addr64.Maximum); |
834 | } |
834 | } |
835 | }; |
835 | }; |
836 | break; |
836 | break; |
837 | }; |
837 | }; |
838 | 838 | ||
839 | return AE_OK; |
839 | return AE_OK; |
840 | }; |
840 | }; |
841 | 841 | ||
842 | 842 | ||
843 | static void print_dm_list() |
843 | static void print_dm_list() |
844 | { |
844 | { |
845 | struct pci_dev *pcidev; |
845 | struct pci_dev *pcidev; |
846 | struct acpi_device *acpidev; |
846 | struct acpi_device *acpidev; |
847 | dmdev_t *dmdev; |
847 | dmdev_t *dmdev; |
848 | uint32_t i; |
848 | uint32_t i; |
849 | 849 | ||
850 | dbgprintf("\nDevices:\n"); |
850 | dbgprintf("\nDevices:\n"); |
851 | 851 | ||
852 | list_for_each_entry(dmdev, &dmdev_tree, list) |
852 | list_for_each_entry(dmdev, &dmdev_tree, list) |
853 | { |
853 | { |
854 | switch(dmdev->type) |
854 | switch(dmdev->type) |
855 | { |
855 | { |
856 | case 0: |
856 | case 0: |
857 | if(dmdev->acpi_dev != NULL) |
857 | if(dmdev->acpi_dev != NULL) |
858 | { |
858 | { |
859 | acpidev = dmdev->acpi_dev; |
859 | acpidev = dmdev->acpi_dev; |
860 | dbgprintf("\n%s\n", acpidev->pnp.bus_id); |
860 | dbgprintf("\n%s\n", acpidev->pnp.bus_id); |
861 | AcpiWalkResources(acpidev->handle, METHOD_NAME__CRS, |
861 | AcpiWalkResources(acpidev->handle, METHOD_NAME__CRS, |
862 | print_acpi_resource, NULL); |
862 | print_acpi_resource, NULL); |
863 | }; |
863 | }; |
864 | break; |
864 | break; |
865 | 865 | ||
866 | case 1: |
866 | case 1: |
867 | if(dmdev->pci_dev != NULL) |
867 | if(dmdev->pci_dev != NULL) |
868 | { |
868 | { |
869 | pcidev = dmdev->pci_dev; |
869 | pcidev = dmdev->pci_dev; |
870 | dbgprintf("\nPCI_%x_%x bus:%d devfn: %x\n", |
870 | dbgprintf("\nPCI_%x_%x bus:%d devfn: %x\n", |
871 | pcidev->vendor, pcidev->device, |
871 | pcidev->vendor, pcidev->device, |
872 | pcidev->busnr, pcidev->devfn); |
872 | pcidev->busnr, pcidev->devfn); |
873 | 873 | ||
874 | for(i = 0; i < DEVICE_COUNT_RESOURCE; i++) |
874 | for(i = 0; i < DEVICE_COUNT_RESOURCE; i++) |
875 | print_pci_resource(&pcidev->resource[i]); |
875 | print_pci_resource(&pcidev->resource[i]); |
876 | 876 | ||
877 | if(pcidev->pin) |
877 | if(pcidev->pin) |
878 | dbgprintf(" APIC IRQ: %d\n", acpi_get_irq(pcidev)); |
878 | dbgprintf(" APIC IRQ: %d\n", acpi_get_irq(pcidev)); |
879 | }; |
879 | }; |
880 | break; |
880 | break; |
881 | }; |
881 | }; |
882 | }; |
882 | }; |
883 | }; |
883 | }; |
884 | 884 | ||
885 | 885 | ||
886 | typedef struct |
886 | typedef struct |
887 | { |
887 | { |
888 | uint32_t busaddr; |
888 | uint32_t busaddr; |
889 | uint32_t devid; |
889 | uint32_t devid; |
890 | uint32_t irq; |
890 | uint32_t irq; |
891 | uint32_t unused; |
891 | uint32_t unused; |
892 | }devinfo_t; |
892 | }devinfo_t; |
893 | 893 | ||
894 | #pragma pack(push, 1) |
894 | #pragma pack(push, 1) |
895 | typedef struct |
895 | typedef struct |
896 | { |
896 | { |
897 | char sec; |
897 | char sec; |
898 | char min; |
898 | char min; |
899 | char hour; |
899 | char hour; |
900 | char rsv; |
900 | char rsv; |
901 | }detime_t; |
901 | }detime_t; |
902 | 902 | ||
903 | typedef struct |
903 | typedef struct |
904 | { |
904 | { |
905 | char day; |
905 | char day; |
906 | char month; |
906 | char month; |
907 | short year; |
907 | short year; |
908 | }dedate_t; |
908 | }dedate_t; |
909 | 909 | ||
910 | typedef struct |
910 | typedef struct |
911 | { |
911 | { |
912 | unsigned attr; |
912 | unsigned attr; |
913 | unsigned flags; |
913 | unsigned flags; |
914 | union |
914 | union |
915 | { |
915 | { |
916 | detime_t ctime; |
916 | detime_t ctime; |
917 | unsigned cr_time; |
917 | unsigned cr_time; |
918 | }; |
918 | }; |
919 | union |
919 | union |
920 | { |
920 | { |
921 | dedate_t cdate; |
921 | dedate_t cdate; |
922 | unsigned cr_date; |
922 | unsigned cr_date; |
923 | }; |
923 | }; |
924 | union |
924 | union |
925 | { |
925 | { |
926 | detime_t atime; |
926 | detime_t atime; |
927 | unsigned acc_time; |
927 | unsigned acc_time; |
928 | }; |
928 | }; |
929 | union |
929 | union |
930 | { |
930 | { |
931 | dedate_t adate; |
931 | dedate_t adate; |
932 | unsigned acc_date; |
932 | unsigned acc_date; |
933 | }; |
933 | }; |
934 | union |
934 | union |
935 | { |
935 | { |
936 | detime_t mtime; |
936 | detime_t mtime; |
937 | unsigned mod_time; |
937 | unsigned mod_time; |
938 | }; |
938 | }; |
939 | union |
939 | union |
940 | { |
940 | { |
941 | dedate_t mdate; |
941 | dedate_t mdate; |
942 | unsigned mod_date; |
942 | unsigned mod_date; |
943 | }; |
943 | }; |
944 | unsigned size; |
944 | unsigned size; |
945 | unsigned size_high; |
945 | unsigned size_high; |
946 | } FILEINFO; |
946 | } FILEINFO; |
947 | 947 | ||
948 | #pragma pack(pop) |
948 | #pragma pack(pop) |
949 | 949 | ||
950 | 950 | ||
951 | int write_device_dat(char *path) |
951 | int write_device_dat(char *path) |
952 | { |
952 | { |
953 | struct pci_dev *pcidev; |
953 | struct pci_dev *pcidev; |
954 | dmdev_t *dmdev; |
954 | dmdev_t *dmdev; |
955 | devinfo_t *data; |
955 | devinfo_t *data; |
956 | int writes; |
956 | int writes; |
957 | int len; |
957 | int len; |
958 | int i = 0; |
958 | int i = 0; |
959 | 959 | ||
960 | list_for_each_entry(dmdev, &dmdev_tree, list) |
960 | list_for_each_entry(dmdev, &dmdev_tree, list) |
961 | { |
961 | { |
962 | if(dmdev->type ==1) |
962 | if(dmdev->type ==1) |
963 | { |
963 | { |
964 | if(dmdev->pci_dev != NULL) |
964 | if(dmdev->pci_dev != NULL) |
965 | { |
965 | { |
966 | pcidev = dmdev->pci_dev; |
966 | pcidev = dmdev->pci_dev; |
967 | if(pcidev->pin) |
967 | if(pcidev->pin) |
968 | i++; |
968 | i++; |
969 | }; |
969 | }; |
970 | }; |
970 | }; |
971 | }; |
971 | }; |
972 | 972 | ||
973 | len = sizeof(devinfo_t)*i + 4; |
973 | len = sizeof(devinfo_t)*i + 4; |
974 | data = (devinfo_t*)malloc(len); |
974 | data = (devinfo_t*)malloc(len); |
975 | 975 | ||
976 | i = 0; |
976 | i = 0; |
977 | 977 | ||
978 | list_for_each_entry(dmdev, &dmdev_tree, list) |
978 | list_for_each_entry(dmdev, &dmdev_tree, list) |
979 | { |
979 | { |
980 | if(dmdev->type == 1) |
980 | if(dmdev->type == 1) |
981 | { |
981 | { |
982 | 982 | ||
983 | if(dmdev->pci_dev != NULL) |
983 | if(dmdev->pci_dev != NULL) |
984 | { |
984 | { |
985 | pcidev = dmdev->pci_dev; |
985 | pcidev = dmdev->pci_dev; |
986 | if(pcidev->pin && (acpi_get_irq(pcidev) != -1) ) |
986 | if(pcidev->pin && (acpi_get_irq(pcidev) != -1) ) |
987 | { |
987 | { |
988 | data[i].busaddr = (pcidev->busnr<<8)|pcidev->devfn; |
988 | data[i].busaddr = (pcidev->busnr<<8)|pcidev->devfn; |
989 | data[i].devid = ((uint32_t)pcidev->device<<16) | |
989 | data[i].devid = ((uint32_t)pcidev->device<<16) | |
990 | pcidev->vendor; |
990 | pcidev->vendor; |
991 | data[i].irq = acpi_get_irq(pcidev); |
991 | data[i].irq = acpi_get_irq(pcidev); |
992 | data[i].unused = 0; |
992 | data[i].unused = 0; |
993 | i++; |
993 | i++; |
994 | } |
994 | } |
995 | }; |
995 | }; |
996 | }; |
996 | }; |
997 | }; |
997 | }; |
998 | 998 | ||
999 | data[i].busaddr = -1; |
999 | data[i].busaddr = -1; |
1000 | 1000 | ||
1001 | FILEINFO info; |
1001 | FILEINFO info; |
1002 | 1002 | ||
1003 | int offset = 0; |
1003 | int offset = 0; |
1004 | 1004 | ||
1005 | if(get_fileinfo(path,&info)) |
1005 | if(get_fileinfo(path,&info)) |
1006 | { |
1006 | { |
1007 | if( create_file(path)) |
1007 | if( create_file(path)) |
1008 | { |
1008 | { |
1009 | free(data); |
1009 | free(data); |
1010 | return false; |
1010 | return false; |
1011 | } |
1011 | } |
1012 | } |
1012 | } |
1013 | else |
1013 | else |
1014 | set_file_size(path, 0); |
1014 | set_file_size(path, 0); |
1015 | 1015 | ||
1016 | write_file(path, data, 0, len, &writes); |
1016 | write_file(path, data, 0, len, &writes); |
1017 | 1017 | ||
1018 | return true; |
1018 | return true; |
1019 | };16)><16)>8)|pcidev-><8)|pcidev->>> |
1019 | };16)><16)>8)|pcidev-><8)|pcidev->>> |