OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [pnp/] [resource.c] - Blame information for rev 65

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * resource.c - Contains functions for registering and analyzing resource information
3
 *
4
 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
5
 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
6
 */
7
 
8
#include <linux/module.h>
9
#include <linux/errno.h>
10
#include <linux/interrupt.h>
11
#include <linux/kernel.h>
12
#include <asm/io.h>
13
#include <asm/dma.h>
14
#include <asm/irq.h>
15
#include <linux/pci.h>
16
#include <linux/ioport.h>
17
#include <linux/init.h>
18
 
19
#include <linux/pnp.h>
20
#include "base.h"
21
 
22
static int pnp_reserve_irq[16] = {[0 ... 15] = -1 };     /* reserve (don't use) some IRQ */
23
static int pnp_reserve_dma[8] = {[0 ... 7] = -1 };       /* reserve (don't use) some DMA */
24
static int pnp_reserve_io[16] = {[0 ... 15] = -1 };      /* reserve (don't use) some I/O region */
25
static int pnp_reserve_mem[16] = {[0 ... 15] = -1 };     /* reserve (don't use) some memory region */
26
 
27
/*
28
 * option registration
29
 */
30
 
31
static struct pnp_option *pnp_build_option(int priority)
32
{
33
        struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
34
 
35
        if (!option)
36
                return NULL;
37
 
38
        option->priority = priority & 0xff;
39
        /* make sure the priority is valid */
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
        return option;
57
}
58
 
59
struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
60
                                                 int priority)
61
{
62
        struct pnp_option *option;
63
 
64
        option = pnp_build_option(priority);
65
 
66
        if (dev->dependent) {
67
                struct pnp_option *parent = dev->dependent;
68
                while (parent->next)
69
                        parent = parent->next;
70
                parent->next = option;
71
        } else
72
                dev->dependent = option;
73
        return option;
74
}
75
 
76
int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
77
{
78
        struct pnp_irq *ptr;
79
 
80
        ptr = option->irq;
81
        while (ptr && ptr->next)
82
                ptr = ptr->next;
83
        if (ptr)
84
                ptr->next = data;
85
        else
86
                option->irq = data;
87
 
88
#ifdef CONFIG_PCI
89
        {
90
                int i;
91
 
92
                for (i = 0; i < 16; i++)
93
                        if (test_bit(i, data->map))
94
                                pcibios_penalize_isa_irq(i, 0);
95
        }
96
#endif
97
        return 0;
98
}
99
 
100
int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data)
101
{
102
        struct pnp_dma *ptr;
103
 
104
        ptr = option->dma;
105
        while (ptr && ptr->next)
106
                ptr = ptr->next;
107
        if (ptr)
108
                ptr->next = data;
109
        else
110
                option->dma = data;
111
 
112
        return 0;
113
}
114
 
115
int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data)
116
{
117
        struct pnp_port *ptr;
118
 
119
        ptr = option->port;
120
        while (ptr && ptr->next)
121
                ptr = ptr->next;
122
        if (ptr)
123
                ptr->next = data;
124
        else
125
                option->port = data;
126
 
127
        return 0;
128
}
129
 
130
int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data)
131
{
132
        struct pnp_mem *ptr;
133
 
134
        ptr = option->mem;
135
        while (ptr && ptr->next)
136
                ptr = ptr->next;
137
        if (ptr)
138
                ptr->next = data;
139
        else
140
                option->mem = data;
141
        return 0;
142
}
143
 
144
static void pnp_free_port(struct pnp_port *port)
145
{
146
        struct pnp_port *next;
147
 
148
        while (port) {
149
                next = port->next;
150
                kfree(port);
151
                port = next;
152
        }
153
}
154
 
155
static void pnp_free_irq(struct pnp_irq *irq)
156
{
157
        struct pnp_irq *next;
158
 
159
        while (irq) {
160
                next = irq->next;
161
                kfree(irq);
162
                irq = next;
163
        }
164
}
165
 
166
static void pnp_free_dma(struct pnp_dma *dma)
167
{
168
        struct pnp_dma *next;
169
 
170
        while (dma) {
171
                next = dma->next;
172
                kfree(dma);
173
                dma = next;
174
        }
175
}
176
 
177
static void pnp_free_mem(struct pnp_mem *mem)
178
{
179
        struct pnp_mem *next;
180
 
181
        while (mem) {
182
                next = mem->next;
183
                kfree(mem);
184
                mem = next;
185
        }
186
}
187
 
188
void pnp_free_option(struct pnp_option *option)
189
{
190
        struct pnp_option *next;
191
 
192
        while (option) {
193
                next = option->next;
194
                pnp_free_port(option->port);
195
                pnp_free_irq(option->irq);
196
                pnp_free_dma(option->dma);
197
                pnp_free_mem(option->mem);
198
                kfree(option);
199
                option = next;
200
        }
201
}
202
 
203
/*
204
 * resource validity checking
205
 */
206
 
207
#define length(start, end) (*(end) - *(start) + 1)
208
 
209
/* Two ranges conflict if one doesn't end before the other starts */
210
#define ranged_conflict(starta, enda, startb, endb) \
211
        !((*(enda) < *(startb)) || (*(endb) < *(starta)))
212
 
213
#define cannot_compare(flags) \
214
((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
215
 
216
int pnp_check_port(struct pnp_dev *dev, int idx)
217
{
218
        int tmp;
219
        struct pnp_dev *tdev;
220
        resource_size_t *port, *end, *tport, *tend;
221
 
222
        port = &dev->res.port_resource[idx].start;
223
        end = &dev->res.port_resource[idx].end;
224
 
225
        /* if the resource doesn't exist, don't complain about it */
226
        if (cannot_compare(dev->res.port_resource[idx].flags))
227
                return 1;
228
 
229
        /* check if the resource is already in use, skip if the
230
         * device is active because it itself may be in use */
231
        if (!dev->active) {
232
                if (__check_region(&ioport_resource, *port, length(port, end)))
233
                        return 0;
234
        }
235
 
236
        /* check if the resource is reserved */
237
        for (tmp = 0; tmp < 8; tmp++) {
238
                int rport = pnp_reserve_io[tmp << 1];
239
                int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1;
240
                if (ranged_conflict(port, end, &rport, &rend))
241
                        return 0;
242
        }
243
 
244
        /* check for internal conflicts */
245
        for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
246
                if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
247
                        tport = &dev->res.port_resource[tmp].start;
248
                        tend = &dev->res.port_resource[tmp].end;
249
                        if (ranged_conflict(port, end, tport, tend))
250
                                return 0;
251
                }
252
        }
253
 
254
        /* check for conflicts with other pnp devices */
255
        pnp_for_each_dev(tdev) {
256
                if (tdev == dev)
257
                        continue;
258
                for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
259
                        if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
260
                                if (cannot_compare
261
                                    (tdev->res.port_resource[tmp].flags))
262
                                        continue;
263
                                tport = &tdev->res.port_resource[tmp].start;
264
                                tend = &tdev->res.port_resource[tmp].end;
265
                                if (ranged_conflict(port, end, tport, tend))
266
                                        return 0;
267
                        }
268
                }
269
        }
270
 
271
        return 1;
272
}
273
 
274
int pnp_check_mem(struct pnp_dev *dev, int idx)
275
{
276
        int tmp;
277
        struct pnp_dev *tdev;
278
        resource_size_t *addr, *end, *taddr, *tend;
279
 
280
        addr = &dev->res.mem_resource[idx].start;
281
        end = &dev->res.mem_resource[idx].end;
282
 
283
        /* if the resource doesn't exist, don't complain about it */
284
        if (cannot_compare(dev->res.mem_resource[idx].flags))
285
                return 1;
286
 
287
        /* check if the resource is already in use, skip if the
288
         * device is active because it itself may be in use */
289
        if (!dev->active) {
290
                if (check_mem_region(*addr, length(addr, end)))
291
                        return 0;
292
        }
293
 
294
        /* check if the resource is reserved */
295
        for (tmp = 0; tmp < 8; tmp++) {
296
                int raddr = pnp_reserve_mem[tmp << 1];
297
                int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1;
298
                if (ranged_conflict(addr, end, &raddr, &rend))
299
                        return 0;
300
        }
301
 
302
        /* check for internal conflicts */
303
        for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) {
304
                if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
305
                        taddr = &dev->res.mem_resource[tmp].start;
306
                        tend = &dev->res.mem_resource[tmp].end;
307
                        if (ranged_conflict(addr, end, taddr, tend))
308
                                return 0;
309
                }
310
        }
311
 
312
        /* check for conflicts with other pnp devices */
313
        pnp_for_each_dev(tdev) {
314
                if (tdev == dev)
315
                        continue;
316
                for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
317
                        if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
318
                                if (cannot_compare
319
                                    (tdev->res.mem_resource[tmp].flags))
320
                                        continue;
321
                                taddr = &tdev->res.mem_resource[tmp].start;
322
                                tend = &tdev->res.mem_resource[tmp].end;
323
                                if (ranged_conflict(addr, end, taddr, tend))
324
                                        return 0;
325
                        }
326
                }
327
        }
328
 
329
        return 1;
330
}
331
 
332
static irqreturn_t pnp_test_handler(int irq, void *dev_id)
333
{
334
        return IRQ_HANDLED;
335
}
336
 
337
int pnp_check_irq(struct pnp_dev *dev, int idx)
338
{
339
        int tmp;
340
        struct pnp_dev *tdev;
341
        resource_size_t *irq = &dev->res.irq_resource[idx].start;
342
 
343
        /* if the resource doesn't exist, don't complain about it */
344
        if (cannot_compare(dev->res.irq_resource[idx].flags))
345
                return 1;
346
 
347
        /* check if the resource is valid */
348
        if (*irq < 0 || *irq > 15)
349
                return 0;
350
 
351
        /* check if the resource is reserved */
352
        for (tmp = 0; tmp < 16; tmp++) {
353
                if (pnp_reserve_irq[tmp] == *irq)
354
                        return 0;
355
        }
356
 
357
        /* check for internal conflicts */
358
        for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
359
                if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
360
                        if (dev->res.irq_resource[tmp].start == *irq)
361
                                return 0;
362
                }
363
        }
364
 
365
#ifdef CONFIG_PCI
366
        /* check if the resource is being used by a pci device */
367
        {
368
                struct pci_dev *pci = NULL;
369
                for_each_pci_dev(pci) {
370
                        if (pci->irq == *irq) {
371
                                pci_dev_put(pci);
372
                                return 0;
373
                        }
374
                }
375
        }
376
#endif
377
 
378
        /* check if the resource is already in use, skip if the
379
         * device is active because it itself may be in use */
380
        if (!dev->active) {
381
                if (request_irq(*irq, pnp_test_handler,
382
                                IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL))
383
                        return 0;
384
                free_irq(*irq, NULL);
385
        }
386
 
387
        /* check for conflicts with other pnp devices */
388
        pnp_for_each_dev(tdev) {
389
                if (tdev == dev)
390
                        continue;
391
                for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
392
                        if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
393
                                if (cannot_compare
394
                                    (tdev->res.irq_resource[tmp].flags))
395
                                        continue;
396
                                if ((tdev->res.irq_resource[tmp].start == *irq))
397
                                        return 0;
398
                        }
399
                }
400
        }
401
 
402
        return 1;
403
}
404
 
405
int pnp_check_dma(struct pnp_dev *dev, int idx)
406
{
407
#ifndef CONFIG_IA64
408
        int tmp;
409
        struct pnp_dev *tdev;
410
        resource_size_t *dma = &dev->res.dma_resource[idx].start;
411
 
412
        /* if the resource doesn't exist, don't complain about it */
413
        if (cannot_compare(dev->res.dma_resource[idx].flags))
414
                return 1;
415
 
416
        /* check if the resource is valid */
417
        if (*dma < 0 || *dma == 4 || *dma > 7)
418
                return 0;
419
 
420
        /* check if the resource is reserved */
421
        for (tmp = 0; tmp < 8; tmp++) {
422
                if (pnp_reserve_dma[tmp] == *dma)
423
                        return 0;
424
        }
425
 
426
        /* check for internal conflicts */
427
        for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
428
                if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
429
                        if (dev->res.dma_resource[tmp].start == *dma)
430
                                return 0;
431
                }
432
        }
433
 
434
        /* check if the resource is already in use, skip if the
435
         * device is active because it itself may be in use */
436
        if (!dev->active) {
437
                if (request_dma(*dma, "pnp"))
438
                        return 0;
439
                free_dma(*dma);
440
        }
441
 
442
        /* check for conflicts with other pnp devices */
443
        pnp_for_each_dev(tdev) {
444
                if (tdev == dev)
445
                        continue;
446
                for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
447
                        if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
448
                                if (cannot_compare
449
                                    (tdev->res.dma_resource[tmp].flags))
450
                                        continue;
451
                                if ((tdev->res.dma_resource[tmp].start == *dma))
452
                                        return 0;
453
                        }
454
                }
455
        }
456
 
457
        return 1;
458
#else
459
        /* IA64 does not have legacy DMA */
460
        return 0;
461
#endif
462
}
463
 
464
/* format is: pnp_reserve_irq=irq1[,irq2] .... */
465
static int __init pnp_setup_reserve_irq(char *str)
466
{
467
        int i;
468
 
469
        for (i = 0; i < 16; i++)
470
                if (get_option(&str, &pnp_reserve_irq[i]) != 2)
471
                        break;
472
        return 1;
473
}
474
 
475
__setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
476
 
477
/* format is: pnp_reserve_dma=dma1[,dma2] .... */
478
static int __init pnp_setup_reserve_dma(char *str)
479
{
480
        int i;
481
 
482
        for (i = 0; i < 8; i++)
483
                if (get_option(&str, &pnp_reserve_dma[i]) != 2)
484
                        break;
485
        return 1;
486
}
487
 
488
__setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
489
 
490
/* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
491
static int __init pnp_setup_reserve_io(char *str)
492
{
493
        int i;
494
 
495
        for (i = 0; i < 16; i++)
496
                if (get_option(&str, &pnp_reserve_io[i]) != 2)
497
                        break;
498
        return 1;
499
}
500
 
501
__setup("pnp_reserve_io=", pnp_setup_reserve_io);
502
 
503
/* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
504
static int __init pnp_setup_reserve_mem(char *str)
505
{
506
        int i;
507
 
508
        for (i = 0; i < 16; i++)
509
                if (get_option(&str, &pnp_reserve_mem[i]) != 2)
510
                        break;
511
        return 1;
512
}
513
 
514
__setup("pnp_reserve_mem=", pnp_setup_reserve_mem);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.