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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [pnp/] [isapnp_proc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  ISA Plug & Play support
3
 *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4
 *
5
 *
6
 *   This program is free software; you can redistribute it and/or modify
7
 *   it under the terms of the GNU General Public License as published by
8
 *   the Free Software Foundation; either version 2 of the License, or
9
 *   (at your option) any later version.
10
 *
11
 *   This program is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU General Public License for more details.
15
 *
16
 *   You should have received a copy of the GNU General Public License
17
 *   along with this program; if not, write to the Free Software
18
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 *
20
 */
21
 
22
#define __NO_VERSION__
23
 
24
#include <linux/kernel.h>
25
#include <linux/module.h>
26
#include <linux/init.h>
27
#include <linux/proc_fs.h>
28
#include <linux/poll.h>
29
#include <linux/vmalloc.h>
30
#include <asm/uaccess.h>
31
#include <linux/smp_lock.h>
32
#include <linux/isapnp.h>
33
 
34
struct isapnp_info_buffer {
35
        char *buffer;           /* pointer to begin of buffer */
36
        char *curr;             /* current position in buffer */
37
        unsigned long size;     /* current size */
38
        unsigned long len;      /* total length of buffer */
39
        int stop;               /* stop flag */
40
        int error;              /* error code */
41
};
42
 
43
typedef struct isapnp_info_buffer isapnp_info_buffer_t;
44
 
45
static struct proc_dir_entry *isapnp_proc_entry = NULL;
46
static struct proc_dir_entry *isapnp_proc_bus_dir = NULL;
47
static struct proc_dir_entry *isapnp_proc_devices_entry = NULL;
48
 
49
static void isapnp_info_read(isapnp_info_buffer_t *buffer);
50
static void isapnp_info_write(isapnp_info_buffer_t *buffer);
51
 
52
int isapnp_printf(isapnp_info_buffer_t * buffer, char *fmt,...)
53
{
54
        va_list args;
55
        int res;
56
        char sbuffer[512];
57
 
58
        if (buffer->stop || buffer->error)
59
                return 0;
60
        va_start(args, fmt);
61
        res = vsprintf(sbuffer, fmt, args);
62
        va_end(args);
63
        if (buffer->size + res >= buffer->len) {
64
                buffer->stop = 1;
65
                return 0;
66
        }
67
        strcpy(buffer->curr, sbuffer);
68
        buffer->curr += res;
69
        buffer->size += res;
70
        return res;
71
}
72
 
73
static void isapnp_devid(char *str, unsigned short vendor, unsigned short device)
74
{
75
        sprintf(str, "%c%c%c%x%x%x%x",
76
                        'A' + ((vendor >> 2) & 0x3f) - 1,
77
                        'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
78
                        'A' + ((vendor >> 8) & 0x1f) - 1,
79
                        (device >> 4) & 0x0f,
80
                        device & 0x0f,
81
                        (device >> 12) & 0x0f,
82
                        (device >> 8) & 0x0f);
83
}
84
 
85
static loff_t isapnp_info_entry_lseek(struct file *file, loff_t offset, int orig)
86
{
87
        switch (orig) {
88
        case 0:  /* SEEK_SET */
89
                file->f_pos = offset;
90
                return file->f_pos;
91
        case 1: /* SEEK_CUR */
92
                file->f_pos += offset;
93
                return file->f_pos;
94
        case 2: /* SEEK_END */
95
        default:
96
                return -EINVAL;
97
        }
98
        return -ENXIO;
99
}
100
 
101
static ssize_t isapnp_info_entry_read(struct file *file, char *buffer,
102
                                      size_t count, loff_t * offset)
103
{
104
        isapnp_info_buffer_t *buf;
105
        long size = 0, size1;
106
        int mode;
107
 
108
        mode = file->f_flags & O_ACCMODE;
109
        if (mode != O_RDONLY)
110
                return -EINVAL;
111
        buf = (isapnp_info_buffer_t *) file->private_data;
112
        if (!buf)
113
                return -EIO;
114
        if (file->f_pos >= buf->size)
115
                return 0;
116
        size = buf->size < count ? buf->size : count;
117
        size1 = buf->size - file->f_pos;
118
        if (size1 < size)
119
                size = size1;
120
        if (copy_to_user(buffer, buf->buffer + file->f_pos, size))
121
                return -EFAULT;
122
        file->f_pos += size;
123
        return size;
124
}
125
 
126
static ssize_t isapnp_info_entry_write(struct file *file, const char *buffer,
127
                                       size_t count, loff_t * offset)
128
{
129
        isapnp_info_buffer_t *buf;
130
        long size = 0, size1;
131
        int mode;
132
 
133
        mode = file->f_flags & O_ACCMODE;
134
        if (mode != O_WRONLY)
135
                return -EINVAL;
136
        buf = (isapnp_info_buffer_t *) file->private_data;
137
        if (!buf)
138
                return -EIO;
139
        if (file->f_pos < 0)
140
                return -EINVAL;
141
        if (file->f_pos >= buf->len)
142
                return -ENOMEM;
143
        size = buf->len < count ? buf->len : count;
144
        size1 = buf->len - file->f_pos;
145
        if (size1 < size)
146
                size = size1;
147
        if (copy_from_user(buf->buffer + file->f_pos, buffer, size))
148
                return -EFAULT;
149
        if (buf->size < file->f_pos + size)
150
                buf->size = file->f_pos + size;
151
        file->f_pos += size;
152
        return size;
153
}
154
 
155
static int isapnp_info_entry_open(struct inode *inode, struct file *file)
156
{
157
        isapnp_info_buffer_t *buffer;
158
        int mode;
159
 
160
        mode = file->f_flags & O_ACCMODE;
161
        if (mode != O_RDONLY && mode != O_WRONLY)
162
                return -EINVAL;
163
        buffer = (isapnp_info_buffer_t *)
164
                                isapnp_alloc(sizeof(isapnp_info_buffer_t));
165
        if (!buffer)
166
                return -ENOMEM;
167
        buffer->len = 4 * PAGE_SIZE;
168
        buffer->buffer = vmalloc(buffer->len);
169
        if (!buffer->buffer) {
170
                kfree(buffer);
171
                return -ENOMEM;
172
        }
173
        lock_kernel();
174
        buffer->curr = buffer->buffer;
175
        file->private_data = buffer;
176
        if (mode == O_RDONLY)
177
                isapnp_info_read(buffer);
178
        unlock_kernel();
179
        return 0;
180
}
181
 
182
static int isapnp_info_entry_release(struct inode *inode, struct file *file)
183
{
184
        isapnp_info_buffer_t *buffer;
185
        int mode;
186
 
187
        if ((buffer = (isapnp_info_buffer_t *) file->private_data) == NULL)
188
                return -EINVAL;
189
        mode = file->f_flags & O_ACCMODE;
190
        lock_kernel();
191
        if (mode == O_WRONLY)
192
                isapnp_info_write(buffer);
193
        vfree(buffer->buffer);
194
        kfree(buffer);
195
        unlock_kernel();
196
        return 0;
197
}
198
 
199
static unsigned int isapnp_info_entry_poll(struct file *file, poll_table * wait)
200
{
201
        if (!file->private_data)
202
                return 0;
203
        return POLLIN | POLLRDNORM;
204
}
205
 
206
static struct file_operations isapnp_info_entry_operations =
207
{
208
        llseek:         isapnp_info_entry_lseek,
209
        read:           isapnp_info_entry_read,
210
        write:          isapnp_info_entry_write,
211
        poll:           isapnp_info_entry_poll,
212
        open:           isapnp_info_entry_open,
213
        release:        isapnp_info_entry_release,
214
};
215
 
216
static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence)
217
{
218
        loff_t new;
219
 
220
        switch (whence) {
221
        case 0:
222
                new = off;
223
                break;
224
        case 1:
225
                new = file->f_pos + off;
226
                break;
227
        case 2:
228
                new = 256 + off;
229
                break;
230
        default:
231
                return -EINVAL;
232
        }
233
        if (new < 0 || new > 256)
234
                return -EINVAL;
235
        return (file->f_pos = new);
236
}
237
 
238
static ssize_t isapnp_proc_bus_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
239
{
240
        struct inode *ino = file->f_dentry->d_inode;
241
        struct proc_dir_entry *dp = ino->u.generic_ip;
242
        struct pci_dev *dev = dp->data;
243
        int pos = *ppos;
244
        int cnt, size = 256;
245
 
246
        if (pos >= size)
247
                return 0;
248
        if (nbytes >= size)
249
                nbytes = size;
250
        if (pos + nbytes > size)
251
                nbytes = size - pos;
252
        cnt = nbytes;
253
 
254
        if (!access_ok(VERIFY_WRITE, buf, cnt))
255
                return -EINVAL;
256
 
257
        isapnp_cfg_begin(dev->bus->number, dev->devfn);
258
        for ( ; pos < 256 && cnt > 0; pos++, buf++, cnt--) {
259
                unsigned char val;
260
                val = isapnp_read_byte(pos);
261
                __put_user(val, buf);
262
        }
263
        isapnp_cfg_end();
264
 
265
        *ppos = pos;
266
        return nbytes;
267
}
268
 
269
static struct file_operations isapnp_proc_bus_file_operations =
270
{
271
        llseek:         isapnp_proc_bus_lseek,
272
        read:           isapnp_proc_bus_read,
273
};
274
 
275
static int isapnp_proc_attach_device(struct pci_dev *dev)
276
{
277
        struct pci_bus *bus = dev->bus;
278
        struct proc_dir_entry *de, *e;
279
        char name[16];
280
 
281
        if (!(de = bus->procdir)) {
282
                sprintf(name, "%02x", bus->number);
283
                de = bus->procdir = proc_mkdir(name, isapnp_proc_bus_dir);
284
                if (!de)
285
                        return -ENOMEM;
286
        }
287
        sprintf(name, "%02x", dev->devfn);
288
        e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de);
289
        if (!e)
290
                return -ENOMEM;
291
        e->proc_fops = &isapnp_proc_bus_file_operations;
292
        e->owner = THIS_MODULE;
293
        e->data = dev;
294
        e->size = 256;
295
        return 0;
296
}
297
 
298
#ifdef MODULE
299
static int __exit isapnp_proc_detach_device(struct pci_dev *dev)
300
{
301
        struct pci_bus *bus = dev->bus;
302
        struct proc_dir_entry *de;
303
        char name[16];
304
 
305
        if (!(de = bus->procdir))
306
                return -EINVAL;
307
        sprintf(name, "%02x", dev->devfn);
308
        remove_proc_entry(name, de);
309
        return 0;
310
}
311
 
312
static int __exit isapnp_proc_detach_bus(struct pci_bus *bus)
313
{
314
        struct proc_dir_entry *de;
315
        char name[16];
316
 
317
        if (!(de = bus->procdir))
318
                return -EINVAL;
319
        sprintf(name, "%02x", bus->number);
320
        remove_proc_entry(name, isapnp_proc_bus_dir);
321
        return 0;
322
}
323
#endif
324
 
325
static int isapnp_proc_read_devices(char *buf, char **start, off_t pos, int count)
326
{
327
        struct pci_dev *dev;
328
        off_t at = 0;
329
        int len, cnt, i;
330
 
331
        cnt = 0;
332
        isapnp_for_each_dev(dev) {
333
                char bus_id[8], device_id[8];
334
 
335
                isapnp_devid(bus_id, dev->bus->vendor, dev->bus->device);
336
                isapnp_devid(device_id, dev->vendor, dev->device);
337
                len = sprintf(buf, "%02x%02x\t%s%s\t",
338
                        dev->bus->number,
339
                        dev->devfn,
340
                        bus_id,
341
                        device_id);
342
                isapnp_cfg_begin(dev->bus->number, dev->devfn);
343
                len += sprintf(buf+len, "%02x", isapnp_read_byte(ISAPNP_CFG_ACTIVATE));
344
                for (i = 0; i < 8; i++)
345
                        len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_PORT + (i << 1)));
346
                for (i = 0; i < 2; i++)
347
                        len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1)));
348
                for (i = 0; i < 2; i++)
349
                        len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_DMA + i));
350
                for (i = 0; i < 4; i++)
351
                        len += sprintf(buf+len, "%08x", isapnp_read_dword(ISAPNP_CFG_MEM + (i << 3)));
352
                isapnp_cfg_end();
353
                buf[len++] = '\n';
354
                at += len;
355
                if (at >= pos) {
356
                        if (!*start) {
357
                                *start = buf + (pos - (at - len));
358
                                cnt = at - pos;
359
                        } else
360
                                cnt += len;
361
                        buf += len;
362
                }
363
        }
364
        return (count > cnt) ? cnt : count;
365
}
366
 
367
int __init isapnp_proc_init(void)
368
{
369
        struct proc_dir_entry *p;
370
        struct pci_dev *dev;
371
 
372
        isapnp_proc_entry = NULL;
373
        p = create_proc_entry("isapnp", S_IFREG | S_IRUGO | S_IWUSR, &proc_root);
374
        if (p) {
375
                p->proc_fops = &isapnp_info_entry_operations;
376
                p->owner = THIS_MODULE;
377
        }
378
        isapnp_proc_entry = p;
379
        isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus);
380
        isapnp_proc_devices_entry = create_proc_info_entry("devices", 0,
381
                                                           isapnp_proc_bus_dir,
382
                                                           isapnp_proc_read_devices);
383
        isapnp_for_each_dev(dev) {
384
                isapnp_proc_attach_device(dev);
385
        }
386
        return 0;
387
}
388
 
389
#ifdef MODULE
390
int __exit isapnp_proc_done(void)
391
{
392
        struct pci_dev *dev;
393
        struct pci_bus *card;
394
 
395
        isapnp_for_each_dev(dev) {
396
                isapnp_proc_detach_device(dev);
397
        }
398
        isapnp_for_each_card(card) {
399
                isapnp_proc_detach_bus(card);
400
        }
401
        if (isapnp_proc_devices_entry)
402
                remove_proc_entry("devices", isapnp_proc_devices_entry);
403
        if (isapnp_proc_bus_dir)
404
                remove_proc_entry("isapnp", proc_bus);
405
        if (isapnp_proc_entry)
406
                remove_proc_entry("isapnp", &proc_root);
407
        return 0;
408
}
409
#endif /* MODULE */
410
 
411
/*
412
 *
413
 */
414
 
415
static void isapnp_print_devid(isapnp_info_buffer_t *buffer, unsigned short vendor, unsigned short device)
416
{
417
        char tmp[8];
418
 
419
        isapnp_devid(tmp, vendor, device);
420
        isapnp_printf(buffer, tmp);
421
}
422
 
423
static void isapnp_print_compatible(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
424
{
425
        int idx;
426
 
427
        for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++) {
428
                if (dev->vendor_compatible[idx] == 0)
429
                        continue;
430
                isapnp_printf(buffer, "    Compatible device ");
431
                isapnp_print_devid(buffer,
432
                                   dev->vendor_compatible[idx],
433
                                   dev->device_compatible[idx]);
434
                isapnp_printf(buffer, "\n");
435
        }
436
}
437
 
438
static void isapnp_print_port(isapnp_info_buffer_t *buffer, char *space, struct isapnp_port *port)
439
{
440
        isapnp_printf(buffer, "%sPort 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
441
                        space, port->min, port->max, port->align ? (port->align-1) : 0, port->size,
442
                        port->flags & ISAPNP_PORT_FLAG_16BITADDR ? 16 : 10);
443
}
444
 
445
static void isapnp_print_irq(isapnp_info_buffer_t *buffer, char *space, struct isapnp_irq *irq)
446
{
447
        int first = 1, i;
448
 
449
        isapnp_printf(buffer, "%sIRQ ", space);
450
        for (i = 0; i < 16; i++)
451
                if (irq->map & (1<<i)) {
452
                        if (!first) {
453
                                isapnp_printf(buffer, ",");
454
                        } else {
455
                                first = 0;
456
                        }
457
                        if (i == 2 || i == 9)
458
                                isapnp_printf(buffer, "2/9");
459
                        else
460
                                isapnp_printf(buffer, "%i", i);
461
                }
462
        if (!irq->map)
463
                isapnp_printf(buffer, "<none>");
464
        if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
465
                isapnp_printf(buffer, " High-Edge");
466
        if (irq->flags & IORESOURCE_IRQ_LOWEDGE)
467
                isapnp_printf(buffer, " Low-Edge");
468
        if (irq->flags & IORESOURCE_IRQ_HIGHLEVEL)
469
                isapnp_printf(buffer, " High-Level");
470
        if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)
471
                isapnp_printf(buffer, " Low-Level");
472
        isapnp_printf(buffer, "\n");
473
}
474
 
475
static void isapnp_print_dma(isapnp_info_buffer_t *buffer, char *space, struct isapnp_dma *dma)
476
{
477
        int first = 1, i;
478
        char *s;
479
 
480
        isapnp_printf(buffer, "%sDMA ", space);
481
        for (i = 0; i < 8; i++)
482
                if (dma->map & (1<<i)) {
483
                        if (!first) {
484
                                isapnp_printf(buffer, ",");
485
                        } else {
486
                                first = 0;
487
                        }
488
                        isapnp_printf(buffer, "%i", i);
489
                }
490
        if (!dma->map)
491
                isapnp_printf(buffer, "<none>");
492
        switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) {
493
        case IORESOURCE_DMA_8BIT:
494
                s = "8-bit";
495
                break;
496
        case IORESOURCE_DMA_8AND16BIT:
497
                s = "8-bit&16-bit";
498
                break;
499
        default:
500
                s = "16-bit";
501
        }
502
        isapnp_printf(buffer, " %s", s);
503
        if (dma->flags & IORESOURCE_DMA_MASTER)
504
                isapnp_printf(buffer, " master");
505
        if (dma->flags & IORESOURCE_DMA_BYTE)
506
                isapnp_printf(buffer, " byte-count");
507
        if (dma->flags & IORESOURCE_DMA_WORD)
508
                isapnp_printf(buffer, " word-count");
509
        switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) {
510
        case IORESOURCE_DMA_TYPEA:
511
                s = "type-A";
512
                break;
513
        case IORESOURCE_DMA_TYPEB:
514
                s = "type-B";
515
                break;
516
        case IORESOURCE_DMA_TYPEF:
517
                s = "type-F";
518
                break;
519
        default:
520
                s = "compatible";
521
                break;
522
        }
523
        isapnp_printf(buffer, " %s\n", s);
524
}
525
 
526
static void isapnp_print_mem(isapnp_info_buffer_t *buffer, char *space, struct isapnp_mem *mem)
527
{
528
        char *s;
529
 
530
        isapnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
531
                        space, mem->min, mem->max, mem->align, mem->size);
532
        if (mem->flags & IORESOURCE_MEM_WRITEABLE)
533
                isapnp_printf(buffer, ", writeable");
534
        if (mem->flags & IORESOURCE_MEM_CACHEABLE)
535
                isapnp_printf(buffer, ", cacheable");
536
        if (mem->flags & IORESOURCE_MEM_RANGELENGTH)
537
                isapnp_printf(buffer, ", range-length");
538
        if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
539
                isapnp_printf(buffer, ", shadowable");
540
        if (mem->flags & IORESOURCE_MEM_EXPANSIONROM)
541
                isapnp_printf(buffer, ", expansion ROM");
542
        switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
543
        case IORESOURCE_MEM_8BIT:
544
                s = "8-bit";
545
                break;
546
        case IORESOURCE_MEM_8AND16BIT:
547
                s = "8-bit&16-bit";
548
                break;
549
        default:
550
                s = "16-bit";
551
        }
552
        isapnp_printf(buffer, ", %s\n", s);
553
}
554
 
555
static void isapnp_print_mem32(isapnp_info_buffer_t *buffer, char *space, struct isapnp_mem32 *mem32)
556
{
557
        int first = 1, i;
558
 
559
        isapnp_printf(buffer, "%s32-bit memory ", space);
560
        for (i = 0; i < 17; i++) {
561
                if (first) {
562
                        first = 0;
563
                } else {
564
                        isapnp_printf(buffer, ":");
565
                }
566
                isapnp_printf(buffer, "%02x", mem32->data[i]);
567
        }
568
}
569
 
570
static void isapnp_print_resources(isapnp_info_buffer_t *buffer, char *space, struct isapnp_resources *res)
571
{
572
        char *s;
573
        struct isapnp_port *port;
574
        struct isapnp_irq *irq;
575
        struct isapnp_dma *dma;
576
        struct isapnp_mem *mem;
577
        struct isapnp_mem32 *mem32;
578
 
579
        switch (res->priority) {
580
        case ISAPNP_RES_PRIORITY_PREFERRED:
581
                s = "preferred";
582
                break;
583
        case ISAPNP_RES_PRIORITY_ACCEPTABLE:
584
                s = "acceptable";
585
                break;
586
        case ISAPNP_RES_PRIORITY_FUNCTIONAL:
587
                s = "functional";
588
                break;
589
        default:
590
                s = "invalid";
591
        }
592
        isapnp_printf(buffer, "%sPriority %s\n", space, s);
593
        for (port = res->port; port; port = port->next)
594
                isapnp_print_port(buffer, space, port);
595
        for (irq = res->irq; irq; irq = irq->next)
596
                isapnp_print_irq(buffer, space, irq);
597
        for (dma = res->dma; dma; dma = dma->next)
598
                isapnp_print_dma(buffer, space, dma);
599
        for (mem = res->mem; mem; mem = mem->next)
600
                isapnp_print_mem(buffer, space, mem);
601
        for (mem32 = res->mem32; mem32; mem32 = mem32->next)
602
                isapnp_print_mem32(buffer, space, mem32);
603
}
604
 
605
static void isapnp_print_configuration(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
606
{
607
        int i, tmp, next;
608
        char *space = "    ";
609
 
610
        isapnp_cfg_begin(dev->bus->number, dev->devfn);
611
        isapnp_printf(buffer, "%sDevice is %sactive\n",
612
                        space, isapnp_read_byte(ISAPNP_CFG_ACTIVATE)?"":"not ");
613
        for (i = next = 0; i < 8; i++) {
614
                tmp = isapnp_read_word(ISAPNP_CFG_PORT + (i << 1));
615
                if (!tmp)
616
                        continue;
617
                if (!next) {
618
                        isapnp_printf(buffer, "%sActive port ", space);
619
                        next = 1;
620
                }
621
                isapnp_printf(buffer, "%s0x%x", i > 0 ? "," : "", tmp);
622
        }
623
        if (next)
624
                isapnp_printf(buffer, "\n");
625
        for (i = next = 0; i < 2; i++) {
626
                tmp = isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1));
627
                if (!(tmp >> 8))
628
                        continue;
629
                if (!next) {
630
                        isapnp_printf(buffer, "%sActive IRQ ", space);
631
                        next = 1;
632
                }
633
                isapnp_printf(buffer, "%s%i", i > 0 ? "," : "", tmp >> 8);
634
                if (tmp & 0xff)
635
                        isapnp_printf(buffer, " [0x%x]", tmp & 0xff);
636
        }
637
        if (next)
638
                isapnp_printf(buffer, "\n");
639
        for (i = next = 0; i < 2; i++) {
640
                tmp = isapnp_read_byte(ISAPNP_CFG_DMA + i);
641
                if (tmp == 4)
642
                        continue;
643
                if (!next) {
644
                        isapnp_printf(buffer, "%sActive DMA ", space);
645
                        next = 1;
646
                }
647
                isapnp_printf(buffer, "%s%i", i > 0 ? "," : "", tmp);
648
        }
649
        if (next)
650
                isapnp_printf(buffer, "\n");
651
        for (i = next = 0; i < 4; i++) {
652
                tmp = isapnp_read_dword(ISAPNP_CFG_MEM + (i << 3));
653
                if (!tmp)
654
                        continue;
655
                if (!next) {
656
                        isapnp_printf(buffer, "%sActive memory ", space);
657
                        next = 1;
658
                }
659
                isapnp_printf(buffer, "%s0x%x", i > 0 ? "," : "", tmp);
660
        }
661
        if (next)
662
                isapnp_printf(buffer, "\n");
663
        isapnp_cfg_end();
664
}
665
 
666
static void isapnp_print_device(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
667
{
668
        int block, block1;
669
        char *space = "    ";
670
        struct isapnp_resources *res, *resa;
671
 
672
        if (!dev)
673
                return;
674
        isapnp_printf(buffer, "  Logical device %i '", dev->devfn);
675
        isapnp_print_devid(buffer, dev->vendor, dev->device);
676
        isapnp_printf(buffer, ":%s'", dev->name[0]?dev->name:"Unknown");
677
        isapnp_printf(buffer, "\n");
678
#if 0
679
        isapnp_cfg_begin(dev->bus->number, dev->devfn);
680
        for (block = 0; block < 128; block++)
681
                if ((block % 16) == 15)
682
                        isapnp_printf(buffer, "%02x\n", isapnp_read_byte(block));
683
                else
684
                        isapnp_printf(buffer, "%02x:", isapnp_read_byte(block));
685
        isapnp_cfg_end();
686
#endif
687
        if (dev->regs)
688
                isapnp_printf(buffer, "%sSupported registers 0x%x\n", space, dev->regs);
689
        isapnp_print_compatible(buffer, dev);
690
        isapnp_print_configuration(buffer, dev);
691
        for (res = (struct isapnp_resources *)dev->sysdata, block = 0; res; res = res->next, block++) {
692
                isapnp_printf(buffer, "%sResources %i\n", space, block);
693
                isapnp_print_resources(buffer, "      ", res);
694
                for (resa = res->alt, block1 = 1; resa; resa = resa->alt, block1++) {
695
                        isapnp_printf(buffer, "%s  Alternate resources %i:%i\n", space, block, block1);
696
                        isapnp_print_resources(buffer, "        ", resa);
697
                }
698
        }
699
}
700
 
701
/*
702
 *  Main read routine
703
 */
704
 
705
static void isapnp_info_read(isapnp_info_buffer_t *buffer)
706
{
707
        struct pci_bus *card;
708
 
709
        isapnp_for_each_card(card) {
710
                struct list_head *dev_list;
711
 
712
                isapnp_printf(buffer, "Card %i '", card->number);
713
                isapnp_print_devid(buffer, card->vendor, card->device);
714
                isapnp_printf(buffer, ":%s'", card->name[0]?card->name:"Unknown");
715
                if (card->pnpver)
716
                        isapnp_printf(buffer, " PnP version %x.%x", card->pnpver >> 4, card->pnpver & 0x0f);
717
                if (card->productver)
718
                        isapnp_printf(buffer, " Product version %x.%x", card->productver >> 4, card->productver & 0x0f);
719
                isapnp_printf(buffer,"\n");
720
                for (dev_list = card->devices.next; dev_list != &card->devices; dev_list = dev_list->next)
721
                        isapnp_print_device(buffer, pci_dev_b(dev_list));
722
        }
723
}
724
 
725
/*
726
 *
727
 */
728
 
729
static struct pci_bus *isapnp_info_card;
730
static struct pci_dev *isapnp_info_device;
731
 
732
static char *isapnp_get_str(char *dest, char *src, int len)
733
{
734
        int c;
735
 
736
        while (*src == ' ' || *src == '\t')
737
                src++;
738
        if (*src == '"' || *src == '\'') {
739
                c = *src++;
740
                while (--len > 0 && *src && *src != c) {
741
                        *dest++ = *src++;
742
                }
743
                if (*src == c)
744
                        src++;
745
        } else {
746
                while (--len > 0 && *src && *src != ' ' && *src != '\t') {
747
                        *dest++ = *src++;
748
                }
749
        }
750
        *dest = 0;
751
        while (*src == ' ' || *src == '\t')
752
                src++;
753
        return src;
754
}
755
 
756
static unsigned char isapnp_get_hex(unsigned char c)
757
{
758
        if (c >= '0' && c <= '9')
759
                return c - '0';
760
        if (c >= 'a' && c <= 'f')
761
                return (c - 'a') + 10;
762
        if (c >= 'A' && c <= 'F')
763
                return (c - 'A') + 10;
764
        return 0;
765
}
766
 
767
static unsigned int isapnp_parse_id(const char *id)
768
{
769
        if (strlen(id) != 7) {
770
                printk("isapnp: wrong PnP ID\n");
771
                return 0;
772
        }
773
        return (ISAPNP_VENDOR(id[0], id[1], id[2])<<16) |
774
                        (isapnp_get_hex(id[3])<<4) |
775
                        (isapnp_get_hex(id[4])<<0) |
776
                        (isapnp_get_hex(id[5])<<12) |
777
                        (isapnp_get_hex(id[6])<<8);
778
}
779
 
780
static int isapnp_set_card(char *line)
781
{
782
        int idx, idx1;
783
        unsigned int id;
784
        char index[16], value[32];
785
 
786
        if (isapnp_info_card) {
787
                isapnp_cfg_end();
788
                isapnp_info_card = NULL;
789
        }
790
        line = isapnp_get_str(index, line, sizeof(index));
791
        isapnp_get_str(value, line, sizeof(value));
792
        idx = idx1 = simple_strtoul(index, NULL, 0);
793
        id = isapnp_parse_id(value);
794
        isapnp_info_card = isapnp_find_card(id >> 16, id & 0xffff, NULL);
795
        while (isapnp_info_card && idx1-- > 0)
796
                isapnp_info_card = isapnp_find_card(id >> 16, id & 0xffff, isapnp_info_card);
797
        if (isapnp_info_card == NULL) {
798
                printk("isapnp: card '%s' order %i not found\n", value, idx);
799
                return 1;
800
        }
801
        if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
802
                printk("isapnp: configuration start sequence for device '%s' failed\n", value);
803
                isapnp_info_card = NULL;
804
                return 1;
805
        }
806
        return 0;
807
}
808
 
809
static int isapnp_select_csn(char *line)
810
{
811
        int csn;
812
        struct list_head *list;
813
        char index[16], value[32];
814
 
815
        isapnp_info_device = NULL;
816
        isapnp_get_str(index, line, sizeof(index));
817
        csn = simple_strtoul(index, NULL, 0);
818
 
819
        for (list = isapnp_cards.next; list != &isapnp_cards; list = list->next) {
820
                isapnp_info_card = pci_bus_b(list);
821
                if (isapnp_info_card->number == csn)
822
                        break;
823
        }
824
        if (list == &isapnp_cards) {
825
                printk("isapnp: cannot find CSN %i\n", csn);
826
                return 1;
827
        }
828
        if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
829
                printk("isapnp: configuration start sequence for device '%s' failed\n", value);
830
                isapnp_info_card = NULL;
831
                return 1;
832
        }
833
        return 0;
834
}
835
 
836
static int isapnp_set_device(char *line)
837
{
838
        int idx, idx1;
839
        unsigned int id;
840
        char index[16], value[32];
841
 
842
        line = isapnp_get_str(index, line, sizeof(index));
843
        isapnp_get_str(value, line, sizeof(value));
844
        idx = idx1 = simple_strtoul(index, NULL, 0);
845
        id = isapnp_parse_id(value);
846
        isapnp_info_device = isapnp_find_dev(isapnp_info_card, id >> 16, id & 0xffff, NULL);
847
        while (isapnp_info_device && idx-- > 0)
848
                isapnp_info_device = isapnp_find_dev(isapnp_info_card, id >> 16, id & 0xffff, isapnp_info_device);
849
        if (isapnp_info_device == NULL) {
850
                printk("isapnp: device '%s' order %i not found\n", value, idx);
851
                return 1;
852
        }
853
        isapnp_device(isapnp_info_device->devfn);
854
        return 0;
855
}
856
 
857
static int isapnp_autoconfigure(void)
858
{
859
        isapnp_cfg_end();
860
        if (isapnp_info_device->active)
861
                isapnp_info_device->deactivate(isapnp_info_device);
862
        if (isapnp_info_device->prepare(isapnp_info_device) < 0) {
863
                printk("isapnp: cannot prepare device for the activation");
864
                return 0;
865
        }
866
        if (isapnp_info_device->activate(isapnp_info_device) < 0) {
867
                printk("isapnp: cannot activate device");
868
                return 0;
869
        }
870
        if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
871
                printk("isapnp: configuration start sequence for card %d failed\n", isapnp_info_card->number);
872
                isapnp_info_card = NULL;
873
                isapnp_info_device = NULL;
874
                return 1;
875
        }
876
        isapnp_device(isapnp_info_device->devfn);
877
        return 0;
878
}
879
 
880
static int isapnp_set_port(char *line)
881
{
882
        int idx, port;
883
        char index[16], value[32];
884
 
885
        line = isapnp_get_str(index, line, sizeof(index));
886
        isapnp_get_str(value, line, sizeof(value));
887
        idx = simple_strtoul(index, NULL, 0);
888
        port = simple_strtoul(value, NULL, 0);
889
        if (idx < 0 || idx > 7) {
890
                printk("isapnp: wrong port index %i\n", idx);
891
                return 1;
892
        }
893
        if (port < 0 || port > 0xffff) {
894
                printk("isapnp: wrong port value 0x%x\n", port);
895
                return 1;
896
        }
897
        isapnp_write_word(ISAPNP_CFG_PORT + (idx << 1), port);
898
        if (!isapnp_info_device->resource[idx].flags)
899
                return 0;
900
        if (isapnp_info_device->resource[idx].flags & IORESOURCE_AUTO) {
901
                isapnp_info_device->resource[idx].start = port;
902
                isapnp_info_device->resource[idx].end += port - 1;
903
                isapnp_info_device->resource[idx].flags &= ~IORESOURCE_AUTO;
904
        } else {
905
                isapnp_info_device->resource[idx].end -= isapnp_info_device->resource[idx].start;
906
                isapnp_info_device->resource[idx].start = port;
907
                isapnp_info_device->resource[idx].end += port;
908
        }
909
        return 0;
910
}
911
 
912
static void isapnp_set_irqresource(struct resource *res, int irq)
913
{
914
        res->start = res->end = irq;
915
        res->flags = IORESOURCE_IRQ;
916
}
917
 
918
static int isapnp_set_irq(char *line)
919
{
920
        int idx, irq;
921
        char index[16], value[32];
922
 
923
        line = isapnp_get_str(index, line, sizeof(index));
924
        isapnp_get_str(value, line, sizeof(value));
925
        idx = simple_strtoul(index, NULL, 0);
926
        irq = simple_strtoul(value, NULL, 0);
927
        if (idx < 0 || idx > 1) {
928
                printk("isapnp: wrong IRQ index %i\n", idx);
929
                return 1;
930
        }
931
        if (irq == 2)
932
                irq = 9;
933
        if (irq < 0 || irq > 15) {
934
                printk("isapnp: wrong IRQ value %i\n", irq);
935
                return 1;
936
        }
937
        isapnp_write_byte(ISAPNP_CFG_IRQ + (idx << 1), irq);
938
        isapnp_set_irqresource(isapnp_info_device->irq_resource + idx, irq);
939
        return 0;
940
}
941
 
942
static void isapnp_set_dmaresource(struct resource *res, int dma)
943
{
944
        res->start = res->end = dma;
945
        res->flags = IORESOURCE_DMA;
946
}
947
 
948
extern int isapnp_allow_dma0;
949
static int isapnp_set_allow_dma0(char *line)
950
{
951
        int i;
952
        char value[32];
953
 
954
        isapnp_get_str(value, line, sizeof(value));
955
        i = simple_strtoul(value, NULL, 0);
956
        if (i < 0 || i > 1) {
957
                printk("isapnp: wrong value %i for allow_dma0\n", i);
958
                return 1;
959
        }
960
        isapnp_allow_dma0 = i;
961
        return 0;
962
}
963
 
964
static int isapnp_set_dma(char *line)
965
{
966
        int idx, dma;
967
        char index[16], value[32];
968
 
969
        line = isapnp_get_str(index, line, sizeof(index));
970
        isapnp_get_str(value, line, sizeof(value));
971
        idx = simple_strtoul(index, NULL, 0);
972
        dma = simple_strtoul(value, NULL, 0);
973
        if (idx < 0 || idx > 1) {
974
                printk("isapnp: wrong DMA index %i\n", idx);
975
                return 1;
976
        }
977
        if (dma < 0 || dma > 7) {
978
                printk("isapnp: wrong DMA value %i\n", dma);
979
                return 1;
980
        }
981
        isapnp_write_byte(ISAPNP_CFG_DMA + idx, dma);
982
        isapnp_set_dmaresource(isapnp_info_device->dma_resource + idx, dma);
983
        return 0;
984
}
985
 
986
static int isapnp_set_mem(char *line)
987
{
988
        int idx;
989
        unsigned int mem;
990
        char index[16], value[32];
991
 
992
        line = isapnp_get_str(index, line, sizeof(index));
993
        isapnp_get_str(value, line, sizeof(value));
994
        idx = simple_strtoul(index, NULL, 0);
995
        mem = simple_strtoul(value, NULL, 0);
996
        if (idx < 0 || idx > 3) {
997
                printk("isapnp: wrong memory index %i\n", idx);
998
                return 1;
999
        }
1000
        mem >>= 8;
1001
        isapnp_write_word(ISAPNP_CFG_MEM + (idx<<2), mem & 0xffff);
1002
        if (!isapnp_info_device->resource[idx + 8].flags)
1003
                return 0;
1004
        if (isapnp_info_device->resource[idx + 8].flags & IORESOURCE_AUTO) {
1005
                isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00;
1006
                isapnp_info_device->resource[idx + 8].end += (mem & ~0x00ffff00) - 1;
1007
                isapnp_info_device->resource[idx + 8].flags &= ~IORESOURCE_AUTO;
1008
        } else {
1009
                isapnp_info_device->resource[idx + 8].end -= isapnp_info_device->resource[idx + 8].start;
1010
                isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00;
1011
                isapnp_info_device->resource[idx + 8].end += mem & ~0x00ffff00;
1012
        }
1013
        return 0;
1014
}
1015
 
1016
static int isapnp_poke(char *line, int what)
1017
{
1018
        int reg;
1019
        unsigned int val;
1020
        char index[16], value[32];
1021
 
1022
        line = isapnp_get_str(index, line, sizeof(index));
1023
        isapnp_get_str(value, line, sizeof(value));
1024
        reg = simple_strtoul(index, NULL, 0);
1025
        val = simple_strtoul(value, NULL, 0);
1026
        if (reg < 0 || reg > 127) {
1027
                printk("isapnp: wrong register %i\n", reg);
1028
                return 1;
1029
        }
1030
        switch (what) {
1031
        case 1:
1032
                isapnp_write_word(reg, val);
1033
                break;
1034
        case 2:
1035
                isapnp_write_dword(reg, val);
1036
                break;
1037
        default:
1038
                isapnp_write_byte(reg, val);
1039
                break;
1040
        }
1041
        return 0;
1042
}
1043
 
1044
static int isapnp_decode_line(char *line)
1045
{
1046
        char cmd[32];
1047
 
1048
        line = isapnp_get_str(cmd, line, sizeof(cmd));
1049
        if (!strcmp(cmd, "allow_dma0"))
1050
                return isapnp_set_allow_dma0(line);
1051
        if (!strcmp(cmd, "card"))
1052
                return isapnp_set_card(line);
1053
        if (!strcmp(cmd, "csn"))
1054
                return isapnp_select_csn(line);
1055
        if (!isapnp_info_card) {
1056
                printk("isapnp: card is not selected\n");
1057
                return 1;
1058
        }
1059
        if (!strncmp(cmd, "dev", 3))
1060
                return isapnp_set_device(line);
1061
        if (!isapnp_info_device) {
1062
                printk("isapnp: device is not selected\n");
1063
                return 1;
1064
        }
1065
        if (!strncmp(cmd, "auto", 4))
1066
                return isapnp_autoconfigure();
1067
        if (!strncmp(cmd, "act", 3)) {
1068
                isapnp_activate(isapnp_info_device->devfn);
1069
                isapnp_info_device->active = 1;
1070
                return 0;
1071
        }
1072
        if (!strncmp(cmd, "deact", 5)) {
1073
                isapnp_deactivate(isapnp_info_device->devfn);
1074
                isapnp_info_device->active = 0;
1075
                return 0;
1076
        }
1077
        if (!strcmp(cmd, "port"))
1078
                return isapnp_set_port(line);
1079
        if (!strcmp(cmd, "irq"))
1080
                return isapnp_set_irq(line);
1081
        if (!strcmp(cmd, "dma"))
1082
                return isapnp_set_dma(line);
1083
        if (!strncmp(cmd, "mem", 3))
1084
                return isapnp_set_mem(line);
1085
        if (!strcmp(cmd, "poke"))
1086
                return isapnp_poke(line, 0);
1087
        if (!strcmp(cmd, "pokew"))
1088
                return isapnp_poke(line, 1);
1089
        if (!strcmp(cmd, "poked"))
1090
                return isapnp_poke(line, 2);
1091
        printk("isapnp: wrong command '%s'\n", cmd);
1092
        return 1;
1093
}
1094
 
1095
/*
1096
 *  Main write routine
1097
 */
1098
 
1099
static void isapnp_info_write(isapnp_info_buffer_t *buffer)
1100
{
1101
        int c, idx, idx1 = 0;
1102
        char line[128];
1103
 
1104
        if (buffer->size <= 0)
1105
                return;
1106
        isapnp_info_card = NULL;
1107
        isapnp_info_device = NULL;
1108
        for (idx = 0; idx < buffer->size; idx++) {
1109
                c = buffer->buffer[idx];
1110
                if (c == '\n') {
1111
                        line[idx1] = '\0';
1112
                        if (line[0] != '#') {
1113
                                if (isapnp_decode_line(line))
1114
                                        goto __end;
1115
                        }
1116
                        idx1 = 0;
1117
                        continue;
1118
                }
1119
                if (idx1 >= sizeof(line)-1) {
1120
                        printk("isapnp: line too long, aborting\n");
1121
                        return;
1122
                }
1123
                line[idx1++] = c;
1124
        }
1125
      __end:
1126
        if (isapnp_info_card)
1127
                isapnp_cfg_end();
1128
}

powered by: WebSVN 2.1.0

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