diff options
Diffstat (limited to 'drivers/pnp/resource.c')
-rw-r--r-- | drivers/pnp/resource.c | 268 |
1 files changed, 65 insertions, 203 deletions
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index a795864dc695..d6388970a1a4 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c | |||
@@ -3,6 +3,8 @@ | |||
3 | * | 3 | * |
4 | * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz> | 4 | * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz> |
5 | * Copyright 2003 Adam Belay <ambx1@neo.rr.com> | 5 | * Copyright 2003 Adam Belay <ambx1@neo.rr.com> |
6 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | ||
7 | * Bjorn Helgaas <bjorn.helgaas@hp.com> | ||
6 | */ | 8 | */ |
7 | 9 | ||
8 | #include <linux/module.h> | 10 | #include <linux/module.h> |
@@ -28,78 +30,36 @@ static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some | |||
28 | * option registration | 30 | * option registration |
29 | */ | 31 | */ |
30 | 32 | ||
31 | struct pnp_option *pnp_build_option(int priority) | 33 | struct pnp_option *pnp_build_option(struct pnp_dev *dev, unsigned long type, |
34 | unsigned int option_flags) | ||
32 | { | 35 | { |
33 | struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option)); | 36 | struct pnp_option *option; |
34 | 37 | ||
38 | option = kzalloc(sizeof(struct pnp_option), GFP_KERNEL); | ||
35 | if (!option) | 39 | if (!option) |
36 | return NULL; | 40 | return NULL; |
37 | 41 | ||
38 | option->priority = priority & 0xff; | 42 | option->flags = option_flags; |
39 | /* make sure the priority is valid */ | 43 | option->type = type; |
40 | if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL) | ||
41 | option->priority = PNP_RES_PRIORITY_INVALID; | ||
42 | |||
43 | return option; | ||
44 | } | ||
45 | |||
46 | struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev) | ||
47 | { | ||
48 | struct pnp_option *option; | ||
49 | |||
50 | option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED); | ||
51 | |||
52 | /* this should never happen but if it does we'll try to continue */ | ||
53 | if (dev->independent) | ||
54 | dev_err(&dev->dev, "independent resource already registered\n"); | ||
55 | dev->independent = option; | ||
56 | |||
57 | dev_dbg(&dev->dev, "new independent option\n"); | ||
58 | return option; | ||
59 | } | ||
60 | |||
61 | struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, | ||
62 | int priority) | ||
63 | { | ||
64 | struct pnp_option *option; | ||
65 | 44 | ||
66 | option = pnp_build_option(priority); | 45 | list_add_tail(&option->list, &dev->options); |
67 | |||
68 | if (dev->dependent) { | ||
69 | struct pnp_option *parent = dev->dependent; | ||
70 | while (parent->next) | ||
71 | parent = parent->next; | ||
72 | parent->next = option; | ||
73 | } else | ||
74 | dev->dependent = option; | ||
75 | |||
76 | dev_dbg(&dev->dev, "new dependent option (priority %#x)\n", priority); | ||
77 | return option; | 46 | return option; |
78 | } | 47 | } |
79 | 48 | ||
80 | int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option, | 49 | int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags, |
81 | pnp_irq_mask_t *map, unsigned char flags) | 50 | pnp_irq_mask_t *map, unsigned char flags) |
82 | { | 51 | { |
83 | struct pnp_irq *irq, *ptr; | 52 | struct pnp_option *option; |
84 | #ifdef DEBUG | 53 | struct pnp_irq *irq; |
85 | char buf[PNP_IRQ_NR]; /* hex-encoded, so this is overkill but safe */ | ||
86 | #endif | ||
87 | 54 | ||
88 | irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL); | 55 | option = pnp_build_option(dev, IORESOURCE_IRQ, option_flags); |
89 | if (!irq) | 56 | if (!option) |
90 | return -ENOMEM; | 57 | return -ENOMEM; |
91 | 58 | ||
59 | irq = &option->u.irq; | ||
92 | irq->map = *map; | 60 | irq->map = *map; |
93 | irq->flags = flags; | 61 | irq->flags = flags; |
94 | 62 | ||
95 | ptr = option->irq; | ||
96 | while (ptr && ptr->next) | ||
97 | ptr = ptr->next; | ||
98 | if (ptr) | ||
99 | ptr->next = irq; | ||
100 | else | ||
101 | option->irq = irq; | ||
102 | |||
103 | #ifdef CONFIG_PCI | 63 | #ifdef CONFIG_PCI |
104 | { | 64 | { |
105 | int i; | 65 | int i; |
@@ -110,163 +70,81 @@ int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option, | |||
110 | } | 70 | } |
111 | #endif | 71 | #endif |
112 | 72 | ||
113 | #ifdef DEBUG | 73 | dbg_pnp_show_option(dev, option); |
114 | bitmap_scnprintf(buf, sizeof(buf), irq->map.bits, PNP_IRQ_NR); | ||
115 | dev_dbg(&dev->dev, " irq bitmask %s flags %#x\n", buf, | ||
116 | irq->flags); | ||
117 | #endif | ||
118 | return 0; | 74 | return 0; |
119 | } | 75 | } |
120 | 76 | ||
121 | int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option, | 77 | int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags, |
122 | unsigned char map, unsigned char flags) | 78 | unsigned char map, unsigned char flags) |
123 | { | 79 | { |
124 | struct pnp_dma *dma, *ptr; | 80 | struct pnp_option *option; |
81 | struct pnp_dma *dma; | ||
125 | 82 | ||
126 | dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL); | 83 | option = pnp_build_option(dev, IORESOURCE_DMA, option_flags); |
127 | if (!dma) | 84 | if (!option) |
128 | return -ENOMEM; | 85 | return -ENOMEM; |
129 | 86 | ||
87 | dma = &option->u.dma; | ||
130 | dma->map = map; | 88 | dma->map = map; |
131 | dma->flags = flags; | 89 | dma->flags = flags; |
132 | 90 | ||
133 | ptr = option->dma; | 91 | dbg_pnp_show_option(dev, option); |
134 | while (ptr && ptr->next) | ||
135 | ptr = ptr->next; | ||
136 | if (ptr) | ||
137 | ptr->next = dma; | ||
138 | else | ||
139 | option->dma = dma; | ||
140 | |||
141 | dev_dbg(&dev->dev, " dma bitmask %#x flags %#x\n", dma->map, | ||
142 | dma->flags); | ||
143 | return 0; | 92 | return 0; |
144 | } | 93 | } |
145 | 94 | ||
146 | int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option, | 95 | int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags, |
147 | resource_size_t min, resource_size_t max, | 96 | resource_size_t min, resource_size_t max, |
148 | resource_size_t align, resource_size_t size, | 97 | resource_size_t align, resource_size_t size, |
149 | unsigned char flags) | 98 | unsigned char flags) |
150 | { | 99 | { |
151 | struct pnp_port *port, *ptr; | 100 | struct pnp_option *option; |
101 | struct pnp_port *port; | ||
152 | 102 | ||
153 | port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); | 103 | option = pnp_build_option(dev, IORESOURCE_IO, option_flags); |
154 | if (!port) | 104 | if (!option) |
155 | return -ENOMEM; | 105 | return -ENOMEM; |
156 | 106 | ||
107 | port = &option->u.port; | ||
157 | port->min = min; | 108 | port->min = min; |
158 | port->max = max; | 109 | port->max = max; |
159 | port->align = align; | 110 | port->align = align; |
160 | port->size = size; | 111 | port->size = size; |
161 | port->flags = flags; | 112 | port->flags = flags; |
162 | 113 | ||
163 | ptr = option->port; | 114 | dbg_pnp_show_option(dev, option); |
164 | while (ptr && ptr->next) | ||
165 | ptr = ptr->next; | ||
166 | if (ptr) | ||
167 | ptr->next = port; | ||
168 | else | ||
169 | option->port = port; | ||
170 | |||
171 | dev_dbg(&dev->dev, " io " | ||
172 | "min %#llx max %#llx align %lld size %lld flags %#x\n", | ||
173 | (unsigned long long) port->min, | ||
174 | (unsigned long long) port->max, | ||
175 | (unsigned long long) port->align, | ||
176 | (unsigned long long) port->size, port->flags); | ||
177 | return 0; | 115 | return 0; |
178 | } | 116 | } |
179 | 117 | ||
180 | int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option, | 118 | int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags, |
181 | resource_size_t min, resource_size_t max, | 119 | resource_size_t min, resource_size_t max, |
182 | resource_size_t align, resource_size_t size, | 120 | resource_size_t align, resource_size_t size, |
183 | unsigned char flags) | 121 | unsigned char flags) |
184 | { | 122 | { |
185 | struct pnp_mem *mem, *ptr; | 123 | struct pnp_option *option; |
124 | struct pnp_mem *mem; | ||
186 | 125 | ||
187 | mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); | 126 | option = pnp_build_option(dev, IORESOURCE_MEM, option_flags); |
188 | if (!mem) | 127 | if (!option) |
189 | return -ENOMEM; | 128 | return -ENOMEM; |
190 | 129 | ||
130 | mem = &option->u.mem; | ||
191 | mem->min = min; | 131 | mem->min = min; |
192 | mem->max = max; | 132 | mem->max = max; |
193 | mem->align = align; | 133 | mem->align = align; |
194 | mem->size = size; | 134 | mem->size = size; |
195 | mem->flags = flags; | 135 | mem->flags = flags; |
196 | 136 | ||
197 | ptr = option->mem; | 137 | dbg_pnp_show_option(dev, option); |
198 | while (ptr && ptr->next) | ||
199 | ptr = ptr->next; | ||
200 | if (ptr) | ||
201 | ptr->next = mem; | ||
202 | else | ||
203 | option->mem = mem; | ||
204 | |||
205 | dev_dbg(&dev->dev, " mem " | ||
206 | "min %#llx max %#llx align %lld size %lld flags %#x\n", | ||
207 | (unsigned long long) mem->min, | ||
208 | (unsigned long long) mem->max, | ||
209 | (unsigned long long) mem->align, | ||
210 | (unsigned long long) mem->size, mem->flags); | ||
211 | return 0; | 138 | return 0; |
212 | } | 139 | } |
213 | 140 | ||
214 | static void pnp_free_port(struct pnp_port *port) | 141 | void pnp_free_options(struct pnp_dev *dev) |
215 | { | ||
216 | struct pnp_port *next; | ||
217 | |||
218 | while (port) { | ||
219 | next = port->next; | ||
220 | kfree(port); | ||
221 | port = next; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | static void pnp_free_irq(struct pnp_irq *irq) | ||
226 | { | ||
227 | struct pnp_irq *next; | ||
228 | |||
229 | while (irq) { | ||
230 | next = irq->next; | ||
231 | kfree(irq); | ||
232 | irq = next; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | static void pnp_free_dma(struct pnp_dma *dma) | ||
237 | { | ||
238 | struct pnp_dma *next; | ||
239 | |||
240 | while (dma) { | ||
241 | next = dma->next; | ||
242 | kfree(dma); | ||
243 | dma = next; | ||
244 | } | ||
245 | } | ||
246 | |||
247 | static void pnp_free_mem(struct pnp_mem *mem) | ||
248 | { | 142 | { |
249 | struct pnp_mem *next; | 143 | struct pnp_option *option, *tmp; |
250 | |||
251 | while (mem) { | ||
252 | next = mem->next; | ||
253 | kfree(mem); | ||
254 | mem = next; | ||
255 | } | ||
256 | } | ||
257 | 144 | ||
258 | void pnp_free_option(struct pnp_option *option) | 145 | list_for_each_entry_safe(option, tmp, &dev->options, list) { |
259 | { | 146 | list_del(&option->list); |
260 | struct pnp_option *next; | ||
261 | |||
262 | while (option) { | ||
263 | next = option->next; | ||
264 | pnp_free_port(option->port); | ||
265 | pnp_free_irq(option->irq); | ||
266 | pnp_free_dma(option->dma); | ||
267 | pnp_free_mem(option->mem); | ||
268 | kfree(option); | 147 | kfree(option); |
269 | option = next; | ||
270 | } | 148 | } |
271 | } | 149 | } |
272 | 150 | ||
@@ -668,66 +546,50 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev, | |||
668 | return pnp_res; | 546 | return pnp_res; |
669 | } | 547 | } |
670 | 548 | ||
671 | static int pnp_possible_option(struct pnp_option *option, int type, | 549 | /* |
672 | resource_size_t start, resource_size_t size) | 550 | * Determine whether the specified resource is a possible configuration |
551 | * for this device. | ||
552 | */ | ||
553 | int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start, | ||
554 | resource_size_t size) | ||
673 | { | 555 | { |
674 | struct pnp_option *tmp; | 556 | struct pnp_option *option; |
675 | struct pnp_port *port; | 557 | struct pnp_port *port; |
676 | struct pnp_mem *mem; | 558 | struct pnp_mem *mem; |
677 | struct pnp_irq *irq; | 559 | struct pnp_irq *irq; |
678 | struct pnp_dma *dma; | 560 | struct pnp_dma *dma; |
679 | 561 | ||
680 | if (!option) | 562 | list_for_each_entry(option, &dev->options, list) { |
681 | return 0; | 563 | if (option->type != type) |
564 | continue; | ||
682 | 565 | ||
683 | for (tmp = option; tmp; tmp = tmp->next) { | 566 | switch (option->type) { |
684 | switch (type) { | ||
685 | case IORESOURCE_IO: | 567 | case IORESOURCE_IO: |
686 | for (port = tmp->port; port; port = port->next) { | 568 | port = &option->u.port; |
687 | if (port->min == start && port->size == size) | 569 | if (port->min == start && port->size == size) |
688 | return 1; | 570 | return 1; |
689 | } | ||
690 | break; | 571 | break; |
691 | case IORESOURCE_MEM: | 572 | case IORESOURCE_MEM: |
692 | for (mem = tmp->mem; mem; mem = mem->next) { | 573 | mem = &option->u.mem; |
693 | if (mem->min == start && mem->size == size) | 574 | if (mem->min == start && mem->size == size) |
694 | return 1; | 575 | return 1; |
695 | } | ||
696 | break; | 576 | break; |
697 | case IORESOURCE_IRQ: | 577 | case IORESOURCE_IRQ: |
698 | for (irq = tmp->irq; irq; irq = irq->next) { | 578 | irq = &option->u.irq; |
699 | if (start < PNP_IRQ_NR && | 579 | if (start < PNP_IRQ_NR && |
700 | test_bit(start, irq->map.bits)) | 580 | test_bit(start, irq->map.bits)) |
701 | return 1; | 581 | return 1; |
702 | } | ||
703 | break; | 582 | break; |
704 | case IORESOURCE_DMA: | 583 | case IORESOURCE_DMA: |
705 | for (dma = tmp->dma; dma; dma = dma->next) { | 584 | dma = &option->u.dma; |
706 | if (dma->map & (1 << start)) | 585 | if (dma->map & (1 << start)) |
707 | return 1; | 586 | return 1; |
708 | } | ||
709 | break; | 587 | break; |
710 | } | 588 | } |
711 | } | 589 | } |
712 | 590 | ||
713 | return 0; | 591 | return 0; |
714 | } | 592 | } |
715 | |||
716 | /* | ||
717 | * Determine whether the specified resource is a possible configuration | ||
718 | * for this device. | ||
719 | */ | ||
720 | int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start, | ||
721 | resource_size_t size) | ||
722 | { | ||
723 | if (pnp_possible_option(dev->independent, type, start, size)) | ||
724 | return 1; | ||
725 | |||
726 | if (pnp_possible_option(dev->dependent, type, start, size)) | ||
727 | return 1; | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | EXPORT_SYMBOL(pnp_possible_config); | 593 | EXPORT_SYMBOL(pnp_possible_config); |
732 | 594 | ||
733 | /* format is: pnp_reserve_irq=irq1[,irq2] .... */ | 595 | /* format is: pnp_reserve_irq=irq1[,irq2] .... */ |