aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pnp/pnpacpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pnp/pnpacpi')
-rw-r--r--drivers/pnp/pnpacpi/Kconfig18
-rw-r--r--drivers/pnp/pnpacpi/Makefile5
-rw-r--r--drivers/pnp/pnpacpi/core.c269
-rw-r--r--drivers/pnp/pnpacpi/pnpacpi.h13
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c821
5 files changed, 1126 insertions, 0 deletions
diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig
new file mode 100644
index 000000000000..0782cdc5009f
--- /dev/null
+++ b/drivers/pnp/pnpacpi/Kconfig
@@ -0,0 +1,18 @@
1#
2# Plug and Play ACPI configuration
3#
4config PNPACPI
5 bool "Plug and Play ACPI support (EXPERIMENTAL)"
6 depends on PNP && ACPI_BUS && EXPERIMENTAL
7 default y
8 ---help---
9 Linux uses the PNPACPI to autodetect built-in
10 mainboard resources (e.g. parallel port resources).
11
12 Some features (e.g. real hotplug) are not currently
13 implemented.
14
15 If you would like the kernel to detect and allocate resources to
16 your mainboard devices (on some systems they are disabled by the
17 BIOS) say Y here. Also the PNPACPI can help prevent resource
18 conflicts between mainboard devices and other bus devices.
diff --git a/drivers/pnp/pnpacpi/Makefile b/drivers/pnp/pnpacpi/Makefile
new file mode 100644
index 000000000000..905326fcca85
--- /dev/null
+++ b/drivers/pnp/pnpacpi/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for the kernel PNPACPI driver.
3#
4
5obj-y := core.o rsparser.o
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
new file mode 100644
index 000000000000..8655dd2e5b83
--- /dev/null
+++ b/drivers/pnp/pnpacpi/core.c
@@ -0,0 +1,269 @@
1/*
2 * pnpacpi -- PnP ACPI driver
3 *
4 * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
5 * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <linux/acpi.h>
23#include <linux/pnp.h>
24#include <acpi/acpi_bus.h>
25#include "pnpacpi.h"
26
27static int num = 0;
28
29static char __initdata excluded_id_list[] =
30 "PNP0C0A," /* Battery */
31 "PNP0C0C,PNP0C0E,PNP0C0D," /* Button */
32 "PNP0C09," /* EC */
33 "PNP0C0B," /* Fan */
34 "PNP0A03," /* PCI root */
35 "PNP0C0F," /* Link device */
36 "PNP0000," /* PIC */
37 "PNP0100," /* Timer */
38 ;
39static inline int is_exclusive_device(struct acpi_device *dev)
40{
41 return (!acpi_match_ids(dev, excluded_id_list));
42}
43
44void *pnpacpi_kmalloc(size_t size, int f)
45{
46 void *p = kmalloc(size, f);
47 if (p)
48 memset(p, 0, size);
49 return p;
50}
51
52/*
53 * Compatible Device IDs
54 */
55#define TEST_HEX(c) \
56 if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \
57 return 0
58#define TEST_ALPHA(c) \
59 if (!('@' <= (c) || (c) <= 'Z')) \
60 return 0
61static int __init ispnpidacpi(char *id)
62{
63 TEST_ALPHA(id[0]);
64 TEST_ALPHA(id[1]);
65 TEST_ALPHA(id[2]);
66 TEST_HEX(id[3]);
67 TEST_HEX(id[4]);
68 TEST_HEX(id[5]);
69 TEST_HEX(id[6]);
70 if (id[7] != '\0')
71 return 0;
72 return 1;
73}
74
75static void __init pnpidacpi_to_pnpid(char *id, char *str)
76{
77 str[0] = id[0];
78 str[1] = id[1];
79 str[2] = id[2];
80 str[3] = tolower(id[3]);
81 str[4] = tolower(id[4]);
82 str[5] = tolower(id[5]);
83 str[6] = tolower(id[6]);
84 str[7] = '\0';
85}
86
87static int pnpacpi_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
88{
89 acpi_status status;
90 status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data,
91 &dev->res);
92 return ACPI_FAILURE(status) ? -ENODEV : 0;
93}
94
95static int pnpacpi_set_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
96{
97 acpi_handle handle = dev->data;
98 struct acpi_buffer buffer;
99 int ret = 0;
100 acpi_status status;
101
102 ret = pnpacpi_build_resource_template(handle, &buffer);
103 if (ret)
104 return ret;
105 ret = pnpacpi_encode_resources(res, &buffer);
106 if (ret) {
107 kfree(buffer.pointer);
108 return ret;
109 }
110 status = acpi_set_current_resources(handle, &buffer);
111 if (ACPI_FAILURE(status))
112 ret = -EINVAL;
113 kfree(buffer.pointer);
114 return ret;
115}
116
117static int pnpacpi_disable_resources(struct pnp_dev *dev)
118{
119 acpi_status status;
120
121 /* acpi_unregister_gsi(pnp_irq(dev, 0)); */
122 status = acpi_evaluate_object((acpi_handle)dev->data,
123 "_DIS", NULL, NULL);
124 return ACPI_FAILURE(status) ? -ENODEV : 0;
125}
126
127struct pnp_protocol pnpacpi_protocol = {
128 .name = "Plug and Play ACPI",
129 .get = pnpacpi_get_resources,
130 .set = pnpacpi_set_resources,
131 .disable = pnpacpi_disable_resources,
132};
133
134static int __init pnpacpi_add_device(struct acpi_device *device)
135{
136 acpi_handle temp = NULL;
137 acpi_status status;
138 struct pnp_id *dev_id;
139 struct pnp_dev *dev;
140
141 if (!ispnpidacpi(acpi_device_hid(device)) ||
142 is_exclusive_device(device))
143 return 0;
144
145 pnp_dbg("ACPI device : hid %s", acpi_device_hid(device));
146 dev = pnpacpi_kmalloc(sizeof(struct pnp_dev), GFP_KERNEL);
147 if (!dev) {
148 pnp_err("Out of memory");
149 return -ENOMEM;
150 }
151 dev->data = device->handle;
152 /* .enabled means if the device can decode the resources */
153 dev->active = device->status.enabled;
154 status = acpi_get_handle(device->handle, "_SRS", &temp);
155 if (ACPI_SUCCESS(status))
156 dev->capabilities |= PNP_CONFIGURABLE;
157 dev->capabilities |= PNP_READ;
158 if (device->flags.dynamic_status)
159 dev->capabilities |= PNP_WRITE;
160 if (device->flags.removable)
161 dev->capabilities |= PNP_REMOVABLE;
162 status = acpi_get_handle(device->handle, "_DIS", &temp);
163 if (ACPI_SUCCESS(status))
164 dev->capabilities |= PNP_DISABLE;
165
166 dev->protocol = &pnpacpi_protocol;
167
168 if (strlen(acpi_device_name(device)))
169 strncpy(dev->name, acpi_device_name(device), sizeof(dev->name));
170 else
171 strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
172
173 dev->number = num;
174
175 /* set the initial values for the PnP device */
176 dev_id = pnpacpi_kmalloc(sizeof(struct pnp_id), GFP_KERNEL);
177 if (!dev_id)
178 goto err;
179 pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
180 pnp_add_id(dev_id, dev);
181
182 if(dev->active) {
183 /* parse allocated resource */
184 status = pnpacpi_parse_allocated_resource(device->handle, &dev->res);
185 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
186 pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s", dev_id->id);
187 goto err1;
188 }
189 }
190
191 if(dev->capabilities & PNP_CONFIGURABLE) {
192 status = pnpacpi_parse_resource_option_data(device->handle,
193 dev);
194 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
195 pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", dev_id->id);
196 goto err1;
197 }
198 }
199
200 /* parse compatible ids */
201 if (device->flags.compatible_ids) {
202 struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
203 int i;
204
205 for (i = 0; i < cid_list->count; i++) {
206 if (!ispnpidacpi(cid_list->id[i].value))
207 continue;
208 dev_id = pnpacpi_kmalloc(sizeof(struct pnp_id),
209 GFP_KERNEL);
210 if (!dev_id)
211 continue;
212
213 pnpidacpi_to_pnpid(cid_list->id[i].value, dev_id->id);
214 pnp_add_id(dev_id, dev);
215 }
216 }
217
218 /* clear out the damaged flags */
219 if (!dev->active)
220 pnp_init_resource_table(&dev->res);
221 pnp_add_device(dev);
222 num ++;
223
224 return AE_OK;
225err1:
226 kfree(dev_id);
227err:
228 kfree(dev);
229 return -EINVAL;
230}
231
232static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
233 u32 lvl, void *context, void **rv)
234{
235 struct acpi_device *device;
236
237 if (!acpi_bus_get_device(handle, &device))
238 pnpacpi_add_device(device);
239 else
240 return AE_CTRL_DEPTH;
241 return AE_OK;
242}
243
244int pnpacpi_disabled __initdata;
245int __init pnpacpi_init(void)
246{
247 if (acpi_disabled || pnpacpi_disabled) {
248 pnp_info("PnP ACPI: disabled");
249 return 0;
250 }
251 pnp_info("PnP ACPI init");
252 pnp_register_protocol(&pnpacpi_protocol);
253 acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL);
254 pnp_info("PnP ACPI: found %d devices", num);
255 return 0;
256}
257subsys_initcall(pnpacpi_init);
258
259static int __init pnpacpi_setup(char *str)
260{
261 if (str == NULL)
262 return 1;
263 if (!strncmp(str, "off", 3))
264 pnpacpi_disabled = 1;
265 return 1;
266}
267__setup("pnpacpi=", pnpacpi_setup);
268
269EXPORT_SYMBOL(pnpacpi_protocol);
diff --git a/drivers/pnp/pnpacpi/pnpacpi.h b/drivers/pnp/pnpacpi/pnpacpi.h
new file mode 100644
index 000000000000..76f907e09ee6
--- /dev/null
+++ b/drivers/pnp/pnpacpi/pnpacpi.h
@@ -0,0 +1,13 @@
1#ifndef ACPI_PNP_H
2#define ACPI_PNP_H
3
4#include <acpi/acpi_bus.h>
5#include <linux/acpi.h>
6#include <linux/pnp.h>
7
8void *pnpacpi_kmalloc(size_t size, int f);
9acpi_status pnpacpi_parse_allocated_resource(acpi_handle, struct pnp_resource_table*);
10acpi_status pnpacpi_parse_resource_option_data(acpi_handle, struct pnp_dev*);
11int pnpacpi_encode_resources(struct pnp_resource_table *, struct acpi_buffer *);
12int pnpacpi_build_resource_template(acpi_handle, struct acpi_buffer*);
13#endif
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
new file mode 100644
index 000000000000..c0ddb1eb8c4d
--- /dev/null
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -0,0 +1,821 @@
1/*
2 * pnpacpi -- PnP ACPI driver
3 *
4 * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
5 * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <linux/kernel.h>
22#include <linux/acpi.h>
23#include <linux/pci.h>
24#include "pnpacpi.h"
25
26#ifdef CONFIG_IA64
27#define valid_IRQ(i) (1)
28#else
29#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
30#endif
31
32/*
33 * Allocated Resources
34 */
35static int irq_flags(int edge_level, int active_high_low)
36{
37 int flag;
38 if (edge_level == ACPI_LEVEL_SENSITIVE) {
39 if(active_high_low == ACPI_ACTIVE_LOW)
40 flag = IORESOURCE_IRQ_LOWLEVEL;
41 else
42 flag = IORESOURCE_IRQ_HIGHLEVEL;
43 }
44 else {
45 if(active_high_low == ACPI_ACTIVE_LOW)
46 flag = IORESOURCE_IRQ_LOWEDGE;
47 else
48 flag = IORESOURCE_IRQ_HIGHEDGE;
49 }
50 return flag;
51}
52
53static void decode_irq_flags(int flag, int *edge_level, int *active_high_low)
54{
55 switch (flag) {
56 case IORESOURCE_IRQ_LOWLEVEL:
57 *edge_level = ACPI_LEVEL_SENSITIVE;
58 *active_high_low = ACPI_ACTIVE_LOW;
59 break;
60 case IORESOURCE_IRQ_HIGHLEVEL:
61 *edge_level = ACPI_LEVEL_SENSITIVE;
62 *active_high_low = ACPI_ACTIVE_HIGH;
63 break;
64 case IORESOURCE_IRQ_LOWEDGE:
65 *edge_level = ACPI_EDGE_SENSITIVE;
66 *active_high_low = ACPI_ACTIVE_LOW;
67 break;
68 case IORESOURCE_IRQ_HIGHEDGE:
69 *edge_level = ACPI_EDGE_SENSITIVE;
70 *active_high_low = ACPI_ACTIVE_HIGH;
71 break;
72 }
73}
74
75static void
76pnpacpi_parse_allocated_irqresource(struct pnp_resource_table * res, int irq)
77{
78 int i = 0;
79 while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
80 i < PNP_MAX_IRQ)
81 i++;
82 if (i < PNP_MAX_IRQ) {
83 res->irq_resource[i].flags = IORESOURCE_IRQ; //Also clears _UNSET flag
84 if (irq == -1) {
85 res->irq_resource[i].flags |= IORESOURCE_DISABLED;
86 return;
87 }
88 res->irq_resource[i].start =(unsigned long) irq;
89 res->irq_resource[i].end = (unsigned long) irq;
90 }
91}
92
93static void
94pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma)
95{
96 int i = 0;
97 while (!(res->dma_resource[i].flags & IORESOURCE_UNSET) &&
98 i < PNP_MAX_DMA)
99 i++;
100 if (i < PNP_MAX_DMA) {
101 res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
102 if (dma == -1) {
103 res->dma_resource[i].flags |= IORESOURCE_DISABLED;
104 return;
105 }
106 res->dma_resource[i].start =(unsigned long) dma;
107 res->dma_resource[i].end = (unsigned long) dma;
108 }
109}
110
111static void
112pnpacpi_parse_allocated_ioresource(struct pnp_resource_table * res,
113 int io, int len)
114{
115 int i = 0;
116 while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
117 i < PNP_MAX_PORT)
118 i++;
119 if (i < PNP_MAX_PORT) {
120 res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
121 if (len <= 0 || (io + len -1) >= 0x10003) {
122 res->port_resource[i].flags |= IORESOURCE_DISABLED;
123 return;
124 }
125 res->port_resource[i].start = (unsigned long) io;
126 res->port_resource[i].end = (unsigned long)(io + len - 1);
127 }
128}
129
130static void
131pnpacpi_parse_allocated_memresource(struct pnp_resource_table * res,
132 int mem, int len)
133{
134 int i = 0;
135 while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
136 (i < PNP_MAX_MEM))
137 i++;
138 if (i < PNP_MAX_MEM) {
139 res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
140 if (len <= 0) {
141 res->mem_resource[i].flags |= IORESOURCE_DISABLED;
142 return;
143 }
144 res->mem_resource[i].start = (unsigned long) mem;
145 res->mem_resource[i].end = (unsigned long)(mem + len - 1);
146 }
147}
148
149
150static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
151 void *data)
152{
153 struct pnp_resource_table * res_table = (struct pnp_resource_table *)data;
154
155 switch (res->id) {
156 case ACPI_RSTYPE_IRQ:
157 if ((res->data.irq.number_of_interrupts > 0) &&
158 valid_IRQ(res->data.irq.interrupts[0])) {
159 pnpacpi_parse_allocated_irqresource(res_table,
160 acpi_register_gsi(res->data.irq.interrupts[0],
161 res->data.irq.edge_level,
162 res->data.irq.active_high_low));
163 pcibios_penalize_isa_irq(res->data.irq.interrupts[0]);
164 }
165 break;
166
167 case ACPI_RSTYPE_EXT_IRQ:
168 if ((res->data.extended_irq.number_of_interrupts > 0) &&
169 valid_IRQ(res->data.extended_irq.interrupts[0])) {
170 pnpacpi_parse_allocated_irqresource(res_table,
171 acpi_register_gsi(res->data.extended_irq.interrupts[0],
172 res->data.extended_irq.edge_level,
173 res->data.extended_irq.active_high_low));
174 pcibios_penalize_isa_irq(res->data.extended_irq.interrupts[0]);
175 }
176 break;
177 case ACPI_RSTYPE_DMA:
178 if (res->data.dma.number_of_channels > 0)
179 pnpacpi_parse_allocated_dmaresource(res_table,
180 res->data.dma.channels[0]);
181 break;
182 case ACPI_RSTYPE_IO:
183 pnpacpi_parse_allocated_ioresource(res_table,
184 res->data.io.min_base_address,
185 res->data.io.range_length);
186 break;
187 case ACPI_RSTYPE_FIXED_IO:
188 pnpacpi_parse_allocated_ioresource(res_table,
189 res->data.fixed_io.base_address,
190 res->data.fixed_io.range_length);
191 break;
192 case ACPI_RSTYPE_MEM24:
193 pnpacpi_parse_allocated_memresource(res_table,
194 res->data.memory24.min_base_address,
195 res->data.memory24.range_length);
196 break;
197 case ACPI_RSTYPE_MEM32:
198 pnpacpi_parse_allocated_memresource(res_table,
199 res->data.memory32.min_base_address,
200 res->data.memory32.range_length);
201 break;
202 case ACPI_RSTYPE_FIXED_MEM32:
203 pnpacpi_parse_allocated_memresource(res_table,
204 res->data.fixed_memory32.range_base_address,
205 res->data.fixed_memory32.range_length);
206 break;
207 case ACPI_RSTYPE_ADDRESS16:
208 pnpacpi_parse_allocated_memresource(res_table,
209 res->data.address16.min_address_range,
210 res->data.address16.address_length);
211 break;
212 case ACPI_RSTYPE_ADDRESS32:
213 pnpacpi_parse_allocated_memresource(res_table,
214 res->data.address32.min_address_range,
215 res->data.address32.address_length);
216 break;
217 case ACPI_RSTYPE_ADDRESS64:
218 pnpacpi_parse_allocated_memresource(res_table,
219 res->data.address64.min_address_range,
220 res->data.address64.address_length);
221 break;
222 case ACPI_RSTYPE_VENDOR:
223 break;
224 default:
225 pnp_warn("PnPACPI: unknown resource type %d", res->id);
226 return AE_ERROR;
227 }
228
229 return AE_OK;
230}
231
232acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle, struct pnp_resource_table * res)
233{
234 /* Blank the resource table values */
235 pnp_init_resource_table(res);
236
237 return acpi_walk_resources(handle, METHOD_NAME__CRS, pnpacpi_allocated_resource, res);
238}
239
240static void pnpacpi_parse_dma_option(struct pnp_option *option, struct acpi_resource_dma *p)
241{
242 int i;
243 struct pnp_dma * dma;
244
245 if (p->number_of_channels == 0)
246 return;
247 dma = pnpacpi_kmalloc(sizeof(struct pnp_dma), GFP_KERNEL);
248 if (!dma)
249 return;
250
251 for(i = 0; i < p->number_of_channels; i++)
252 dma->map |= 1 << p->channels[i];
253 dma->flags = 0;
254 if (p->bus_master)
255 dma->flags |= IORESOURCE_DMA_MASTER;
256 switch (p->type) {
257 case ACPI_COMPATIBILITY:
258 dma->flags |= IORESOURCE_DMA_COMPATIBLE;
259 break;
260 case ACPI_TYPE_A:
261 dma->flags |= IORESOURCE_DMA_TYPEA;
262 break;
263 case ACPI_TYPE_B:
264 dma->flags |= IORESOURCE_DMA_TYPEB;
265 break;
266 case ACPI_TYPE_F:
267 dma->flags |= IORESOURCE_DMA_TYPEF;
268 break;
269 default:
270 /* Set a default value ? */
271 dma->flags |= IORESOURCE_DMA_COMPATIBLE;
272 pnp_err("Invalid DMA type");
273 }
274 switch (p->transfer) {
275 case ACPI_TRANSFER_8:
276 dma->flags |= IORESOURCE_DMA_8BIT;
277 break;
278 case ACPI_TRANSFER_8_16:
279 dma->flags |= IORESOURCE_DMA_8AND16BIT;
280 break;
281 case ACPI_TRANSFER_16:
282 dma->flags |= IORESOURCE_DMA_16BIT;
283 break;
284 default:
285 /* Set a default value ? */
286 dma->flags |= IORESOURCE_DMA_8AND16BIT;
287 pnp_err("Invalid DMA transfer type");
288 }
289
290 pnp_register_dma_resource(option,dma);
291 return;
292}
293
294
295static void pnpacpi_parse_irq_option(struct pnp_option *option,
296 struct acpi_resource_irq *p)
297{
298 int i;
299 struct pnp_irq * irq;
300
301 if (p->number_of_interrupts == 0)
302 return;
303 irq = pnpacpi_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
304 if (!irq)
305 return;
306
307 for(i = 0; i < p->number_of_interrupts; i++)
308 if (p->interrupts[i])
309 __set_bit(p->interrupts[i], irq->map);
310 irq->flags = irq_flags(p->edge_level, p->active_high_low);
311
312 pnp_register_irq_resource(option, irq);
313 return;
314}
315
316static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
317 struct acpi_resource_ext_irq *p)
318{
319 int i;
320 struct pnp_irq * irq;
321
322 if (p->number_of_interrupts == 0)
323 return;
324 irq = pnpacpi_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
325 if (!irq)
326 return;
327
328 for(i = 0; i < p->number_of_interrupts; i++)
329 if (p->interrupts[i])
330 __set_bit(p->interrupts[i], irq->map);
331 irq->flags = irq_flags(p->edge_level, p->active_high_low);
332
333 pnp_register_irq_resource(option, irq);
334 return;
335}
336
337static void
338pnpacpi_parse_port_option(struct pnp_option *option,
339 struct acpi_resource_io *io)
340{
341 struct pnp_port * port;
342
343 if (io->range_length == 0)
344 return;
345 port = pnpacpi_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
346 if (!port)
347 return;
348 port->min = io->min_base_address;
349 port->max = io->max_base_address;
350 port->align = io->alignment;
351 port->size = io->range_length;
352 port->flags = ACPI_DECODE_16 == io->io_decode ?
353 PNP_PORT_FLAG_16BITADDR : 0;
354 pnp_register_port_resource(option,port);
355 return;
356}
357
358static void
359pnpacpi_parse_fixed_port_option(struct pnp_option *option,
360 struct acpi_resource_fixed_io *io)
361{
362 struct pnp_port * port;
363
364 if (io->range_length == 0)
365 return;
366 port = pnpacpi_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
367 if (!port)
368 return;
369 port->min = port->max = io->base_address;
370 port->size = io->range_length;
371 port->align = 0;
372 port->flags = PNP_PORT_FLAG_FIXED;
373 pnp_register_port_resource(option,port);
374 return;
375}
376
377static void
378pnpacpi_parse_mem24_option(struct pnp_option *option,
379 struct acpi_resource_mem24 *p)
380{
381 struct pnp_mem * mem;
382
383 if (p->range_length == 0)
384 return;
385 mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
386 if (!mem)
387 return;
388 mem->min = p->min_base_address;
389 mem->max = p->max_base_address;
390 mem->align = p->alignment;
391 mem->size = p->range_length;
392
393 mem->flags = (ACPI_READ_WRITE_MEMORY == p->read_write_attribute) ?
394 IORESOURCE_MEM_WRITEABLE : 0;
395
396 pnp_register_mem_resource(option,mem);
397 return;
398}
399
400static void
401pnpacpi_parse_mem32_option(struct pnp_option *option,
402 struct acpi_resource_mem32 *p)
403{
404 struct pnp_mem * mem;
405
406 if (p->range_length == 0)
407 return;
408 mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
409 if (!mem)
410 return;
411 mem->min = p->min_base_address;
412 mem->max = p->max_base_address;
413 mem->align = p->alignment;
414 mem->size = p->range_length;
415
416 mem->flags = (ACPI_READ_WRITE_MEMORY == p->read_write_attribute) ?
417 IORESOURCE_MEM_WRITEABLE : 0;
418
419 pnp_register_mem_resource(option,mem);
420 return;
421}
422
423static void
424pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
425 struct acpi_resource_fixed_mem32 *p)
426{
427 struct pnp_mem * mem;
428
429 if (p->range_length == 0)
430 return;
431 mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
432 if (!mem)
433 return;
434 mem->min = mem->max = p->range_base_address;
435 mem->size = p->range_length;
436 mem->align = 0;
437
438 mem->flags = (ACPI_READ_WRITE_MEMORY == p->read_write_attribute) ?
439 IORESOURCE_MEM_WRITEABLE : 0;
440
441 pnp_register_mem_resource(option,mem);
442 return;
443}
444
445struct acpipnp_parse_option_s {
446 struct pnp_option *option;
447 struct pnp_dev *dev;
448};
449
450static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
451 void *data)
452{
453 int priority = 0;
454 struct acpipnp_parse_option_s *parse_data = (struct acpipnp_parse_option_s *)data;
455 struct pnp_dev *dev = parse_data->dev;
456 struct pnp_option *option = parse_data->option;
457
458 switch (res->id) {
459 case ACPI_RSTYPE_IRQ:
460 pnpacpi_parse_irq_option(option, &res->data.irq);
461 break;
462 case ACPI_RSTYPE_EXT_IRQ:
463 pnpacpi_parse_ext_irq_option(option,
464 &res->data.extended_irq);
465 break;
466 case ACPI_RSTYPE_DMA:
467 pnpacpi_parse_dma_option(option, &res->data.dma);
468 break;
469 case ACPI_RSTYPE_IO:
470 pnpacpi_parse_port_option(option, &res->data.io);
471 break;
472 case ACPI_RSTYPE_FIXED_IO:
473 pnpacpi_parse_fixed_port_option(option,
474 &res->data.fixed_io);
475 break;
476 case ACPI_RSTYPE_MEM24:
477 pnpacpi_parse_mem24_option(option, &res->data.memory24);
478 break;
479 case ACPI_RSTYPE_MEM32:
480 pnpacpi_parse_mem32_option(option, &res->data.memory32);
481 break;
482 case ACPI_RSTYPE_FIXED_MEM32:
483 pnpacpi_parse_fixed_mem32_option(option,
484 &res->data.fixed_memory32);
485 break;
486 case ACPI_RSTYPE_START_DPF:
487 switch (res->data.start_dpf.compatibility_priority) {
488 case ACPI_GOOD_CONFIGURATION:
489 priority = PNP_RES_PRIORITY_PREFERRED;
490 break;
491
492 case ACPI_ACCEPTABLE_CONFIGURATION:
493 priority = PNP_RES_PRIORITY_ACCEPTABLE;
494 break;
495
496 case ACPI_SUB_OPTIMAL_CONFIGURATION:
497 priority = PNP_RES_PRIORITY_FUNCTIONAL;
498 break;
499 default:
500 priority = PNP_RES_PRIORITY_INVALID;
501 break;
502 }
503 /* TBD: Considering performace/robustness bits */
504 option = pnp_register_dependent_option(dev, priority);
505 if (!option)
506 return AE_ERROR;
507 parse_data->option = option;
508 break;
509 case ACPI_RSTYPE_END_DPF:
510 return AE_CTRL_TERMINATE;
511 default:
512 pnp_warn("PnPACPI: unknown resource type %d", res->id);
513 return AE_ERROR;
514 }
515
516 return AE_OK;
517}
518
519acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
520 struct pnp_dev *dev)
521{
522 acpi_status status;
523 struct acpipnp_parse_option_s parse_data;
524
525 parse_data.option = pnp_register_independent_option(dev);
526 if (!parse_data.option)
527 return AE_ERROR;
528 parse_data.dev = dev;
529 status = acpi_walk_resources(handle, METHOD_NAME__PRS,
530 pnpacpi_option_resource, &parse_data);
531
532 return status;
533}
534
535/*
536 * Set resource
537 */
538static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
539 void *data)
540{
541 int *res_cnt = (int *)data;
542 switch (res->id) {
543 case ACPI_RSTYPE_IRQ:
544 case ACPI_RSTYPE_EXT_IRQ:
545 case ACPI_RSTYPE_DMA:
546 case ACPI_RSTYPE_IO:
547 case ACPI_RSTYPE_FIXED_IO:
548 case ACPI_RSTYPE_MEM24:
549 case ACPI_RSTYPE_MEM32:
550 case ACPI_RSTYPE_FIXED_MEM32:
551#if 0
552 case ACPI_RSTYPE_ADDRESS16:
553 case ACPI_RSTYPE_ADDRESS32:
554 case ACPI_RSTYPE_ADDRESS64:
555#endif
556 (*res_cnt) ++;
557 default:
558 return AE_OK;
559 }
560 return AE_OK;
561}
562
563static acpi_status pnpacpi_type_resources(struct acpi_resource *res,
564 void *data)
565{
566 struct acpi_resource **resource = (struct acpi_resource **)data;
567 switch (res->id) {
568 case ACPI_RSTYPE_IRQ:
569 case ACPI_RSTYPE_EXT_IRQ:
570 case ACPI_RSTYPE_DMA:
571 case ACPI_RSTYPE_IO:
572 case ACPI_RSTYPE_FIXED_IO:
573 case ACPI_RSTYPE_MEM24:
574 case ACPI_RSTYPE_MEM32:
575 case ACPI_RSTYPE_FIXED_MEM32:
576#if 0
577 case ACPI_RSTYPE_ADDRESS16:
578 case ACPI_RSTYPE_ADDRESS32:
579 case ACPI_RSTYPE_ADDRESS64:
580#endif
581 (*resource)->id = res->id;
582 (*resource)++;
583 default:
584 return AE_OK;
585 }
586
587 return AE_OK;
588}
589
590int pnpacpi_build_resource_template(acpi_handle handle,
591 struct acpi_buffer *buffer)
592{
593 struct acpi_resource *resource;
594 int res_cnt = 0;
595 acpi_status status;
596
597 status = acpi_walk_resources(handle, METHOD_NAME__CRS,
598 pnpacpi_count_resources, &res_cnt);
599 if (ACPI_FAILURE(status)) {
600 pnp_err("Evaluate _CRS failed");
601 return -EINVAL;
602 }
603 if (!res_cnt)
604 return -EINVAL;
605 buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
606 buffer->pointer = pnpacpi_kmalloc(buffer->length - 1, GFP_KERNEL);
607 if (!buffer->pointer)
608 return -ENOMEM;
609 pnp_dbg("Res cnt %d", res_cnt);
610 resource = (struct acpi_resource *)buffer->pointer;
611 status = acpi_walk_resources(handle, METHOD_NAME__CRS,
612 pnpacpi_type_resources, &resource);
613 if (ACPI_FAILURE(status)) {
614 kfree(buffer->pointer);
615 pnp_err("Evaluate _CRS failed");
616 return -EINVAL;
617 }
618 /* resource will pointer the end resource now */
619 resource->id = ACPI_RSTYPE_END_TAG;
620
621 return 0;
622}
623
624static void pnpacpi_encode_irq(struct acpi_resource *resource,
625 struct resource *p)
626{
627 int edge_level, active_high_low;
628
629 decode_irq_flags(p->flags & IORESOURCE_BITS, &edge_level,
630 &active_high_low);
631 resource->id = ACPI_RSTYPE_IRQ;
632 resource->length = sizeof(struct acpi_resource);
633 resource->data.irq.edge_level = edge_level;
634 resource->data.irq.active_high_low = active_high_low;
635 if (edge_level == ACPI_EDGE_SENSITIVE)
636 resource->data.irq.shared_exclusive = ACPI_EXCLUSIVE;
637 else
638 resource->data.irq.shared_exclusive = ACPI_SHARED;
639 resource->data.irq.number_of_interrupts = 1;
640 resource->data.irq.interrupts[0] = p->start;
641}
642
643static void pnpacpi_encode_ext_irq(struct acpi_resource *resource,
644 struct resource *p)
645{
646 int edge_level, active_high_low;
647
648 decode_irq_flags(p->flags & IORESOURCE_BITS, &edge_level,
649 &active_high_low);
650 resource->id = ACPI_RSTYPE_EXT_IRQ;
651 resource->length = sizeof(struct acpi_resource);
652 resource->data.extended_irq.producer_consumer = ACPI_CONSUMER;
653 resource->data.extended_irq.edge_level = edge_level;
654 resource->data.extended_irq.active_high_low = active_high_low;
655 if (edge_level == ACPI_EDGE_SENSITIVE)
656 resource->data.irq.shared_exclusive = ACPI_EXCLUSIVE;
657 else
658 resource->data.irq.shared_exclusive = ACPI_SHARED;
659 resource->data.extended_irq.number_of_interrupts = 1;
660 resource->data.extended_irq.interrupts[0] = p->start;
661}
662
663static void pnpacpi_encode_dma(struct acpi_resource *resource,
664 struct resource *p)
665{
666 resource->id = ACPI_RSTYPE_DMA;
667 resource->length = sizeof(struct acpi_resource);
668 /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
669 if (p->flags & IORESOURCE_DMA_COMPATIBLE)
670 resource->data.dma.type = ACPI_COMPATIBILITY;
671 else if (p->flags & IORESOURCE_DMA_TYPEA)
672 resource->data.dma.type = ACPI_TYPE_A;
673 else if (p->flags & IORESOURCE_DMA_TYPEB)
674 resource->data.dma.type = ACPI_TYPE_B;
675 else if (p->flags & IORESOURCE_DMA_TYPEF)
676 resource->data.dma.type = ACPI_TYPE_F;
677 if (p->flags & IORESOURCE_DMA_8BIT)
678 resource->data.dma.transfer = ACPI_TRANSFER_8;
679 else if (p->flags & IORESOURCE_DMA_8AND16BIT)
680 resource->data.dma.transfer = ACPI_TRANSFER_8_16;
681 else if (p->flags & IORESOURCE_DMA_16BIT)
682 resource->data.dma.transfer = ACPI_TRANSFER_16;
683 resource->data.dma.bus_master = p->flags & IORESOURCE_DMA_MASTER;
684 resource->data.dma.number_of_channels = 1;
685 resource->data.dma.channels[0] = p->start;
686}
687
688static void pnpacpi_encode_io(struct acpi_resource *resource,
689 struct resource *p)
690{
691 resource->id = ACPI_RSTYPE_IO;
692 resource->length = sizeof(struct acpi_resource);
693 /* Note: pnp_assign_port will copy pnp_port->flags into p->flags */
694 resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR)?
695 ACPI_DECODE_16 : ACPI_DECODE_10;
696 resource->data.io.min_base_address = p->start;
697 resource->data.io.max_base_address = p->end;
698 resource->data.io.alignment = 0; /* Correct? */
699 resource->data.io.range_length = p->end - p->start + 1;
700}
701
702static void pnpacpi_encode_fixed_io(struct acpi_resource *resource,
703 struct resource *p)
704{
705 resource->id = ACPI_RSTYPE_FIXED_IO;
706 resource->length = sizeof(struct acpi_resource);
707 resource->data.fixed_io.base_address = p->start;
708 resource->data.fixed_io.range_length = p->end - p->start + 1;
709}
710
711static void pnpacpi_encode_mem24(struct acpi_resource *resource,
712 struct resource *p)
713{
714 resource->id = ACPI_RSTYPE_MEM24;
715 resource->length = sizeof(struct acpi_resource);
716 /* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */
717 resource->data.memory24.read_write_attribute =
718 (p->flags & IORESOURCE_MEM_WRITEABLE) ?
719 ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
720 resource->data.memory24.min_base_address = p->start;
721 resource->data.memory24.max_base_address = p->end;
722 resource->data.memory24.alignment = 0;
723 resource->data.memory24.range_length = p->end - p->start + 1;
724}
725
726static void pnpacpi_encode_mem32(struct acpi_resource *resource,
727 struct resource *p)
728{
729 resource->id = ACPI_RSTYPE_MEM32;
730 resource->length = sizeof(struct acpi_resource);
731 resource->data.memory32.read_write_attribute =
732 (p->flags & IORESOURCE_MEM_WRITEABLE) ?
733 ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
734 resource->data.memory32.min_base_address = p->start;
735 resource->data.memory32.max_base_address = p->end;
736 resource->data.memory32.alignment = 0;
737 resource->data.memory32.range_length = p->end - p->start + 1;
738}
739
740static void pnpacpi_encode_fixed_mem32(struct acpi_resource *resource,
741 struct resource *p)
742{
743 resource->id = ACPI_RSTYPE_FIXED_MEM32;
744 resource->length = sizeof(struct acpi_resource);
745 resource->data.fixed_memory32.read_write_attribute =
746 (p->flags & IORESOURCE_MEM_WRITEABLE) ?
747 ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
748 resource->data.fixed_memory32.range_base_address = p->start;
749 resource->data.fixed_memory32.range_length = p->end - p->start + 1;
750}
751
752int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
753 struct acpi_buffer *buffer)
754{
755 int i = 0;
756 /* pnpacpi_build_resource_template allocates extra mem */
757 int res_cnt = (buffer->length - 1)/sizeof(struct acpi_resource) - 1;
758 struct acpi_resource *resource = (struct acpi_resource*)buffer->pointer;
759 int port = 0, irq = 0, dma = 0, mem = 0;
760
761 pnp_dbg("res cnt %d", res_cnt);
762 while (i < res_cnt) {
763 switch(resource->id) {
764 case ACPI_RSTYPE_IRQ:
765 pnp_dbg("Encode irq");
766 pnpacpi_encode_irq(resource,
767 &res_table->irq_resource[irq]);
768 irq++;
769 break;
770
771 case ACPI_RSTYPE_EXT_IRQ:
772 pnp_dbg("Encode ext irq");
773 pnpacpi_encode_ext_irq(resource,
774 &res_table->irq_resource[irq]);
775 irq++;
776 break;
777 case ACPI_RSTYPE_DMA:
778 pnp_dbg("Encode dma");
779 pnpacpi_encode_dma(resource,
780 &res_table->dma_resource[dma]);
781 dma ++;
782 break;
783 case ACPI_RSTYPE_IO:
784 pnp_dbg("Encode io");
785 pnpacpi_encode_io(resource,
786 &res_table->port_resource[port]);
787 port ++;
788 break;
789 case ACPI_RSTYPE_FIXED_IO:
790 pnp_dbg("Encode fixed io");
791 pnpacpi_encode_fixed_io(resource,
792 &res_table->port_resource[port]);
793 port ++;
794 break;
795 case ACPI_RSTYPE_MEM24:
796 pnp_dbg("Encode mem24");
797 pnpacpi_encode_mem24(resource,
798 &res_table->mem_resource[mem]);
799 mem ++;
800 break;
801 case ACPI_RSTYPE_MEM32:
802 pnp_dbg("Encode mem32");
803 pnpacpi_encode_mem32(resource,
804 &res_table->mem_resource[mem]);
805 mem ++;
806 break;
807 case ACPI_RSTYPE_FIXED_MEM32:
808 pnp_dbg("Encode fixed mem32");
809 pnpacpi_encode_fixed_mem32(resource,
810 &res_table->mem_resource[mem]);
811 mem ++;
812 break;
813 default: /* other type */
814 pnp_warn("unknown resource type %d", resource->id);
815 return -EINVAL;
816 }
817 resource ++;
818 i ++;
819 }
820 return 0;
821}