~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/pnp/isapnp_proc.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  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 >= '' && c <= '9')
759                 return c - '';
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         isapnp_info_card = NULL;
787         line = isapnp_get_str(index, line, sizeof(index));
788         isapnp_get_str(value, line, sizeof(value));
789         idx = idx1 = simple_strtoul(index, NULL, 0);
790         id = isapnp_parse_id(value);
791         isapnp_info_card = isapnp_find_card(id >> 16, id & 0xffff, NULL);
792         while (isapnp_info_card && idx1-- > 0)
793                 isapnp_info_card = isapnp_find_card(id >> 16, id & 0xffff, isapnp_info_card);
794         if (isapnp_info_card == NULL) {
795                 printk("isapnp: card '%s' order %i not found\n", value, idx);
796                 return 1;
797         }
798         if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
799                 printk("isapnp: configuration start sequence for device '%s' failed\n", value);
800                 isapnp_info_card = NULL;
801                 return 1;
802         }
803         return 0;
804 }
805 
806 static int isapnp_select_csn(char *line)
807 {
808         int csn;
809         struct list_head *list;
810         char index[16], value[32];
811 
812         isapnp_info_device = NULL;
813         isapnp_get_str(index, line, sizeof(index));
814         csn = simple_strtoul(index, NULL, 0);
815 
816         for (list = isapnp_cards.next; list != &isapnp_cards; list = list->next) {
817                 isapnp_info_card = pci_bus_b(list);
818                 if (isapnp_info_card->number == csn)
819                         break;
820         }
821         if (list == &isapnp_cards) {
822                 printk("isapnp: cannot find CSN %i\n", csn);
823                 return 1;
824         }
825         if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
826                 printk("isapnp: configuration start sequence for device '%s' failed\n", value);
827                 isapnp_info_card = NULL;
828                 return 1;
829         }
830         return 0;
831 }
832 
833 static int isapnp_set_device(char *line)
834 {
835         int idx, idx1;
836         unsigned int id;
837         char index[16], value[32];
838 
839         line = isapnp_get_str(index, line, sizeof(index));
840         isapnp_get_str(value, line, sizeof(value));
841         idx = idx1 = simple_strtoul(index, NULL, 0);
842         id = isapnp_parse_id(value);
843         isapnp_info_device = isapnp_find_dev(isapnp_info_card, id >> 16, id & 0xffff, NULL);
844         while (isapnp_info_device && idx-- > 0)
845                 isapnp_info_device = isapnp_find_dev(isapnp_info_card, id >> 16, id & 0xffff, isapnp_info_device);
846         if (isapnp_info_device == NULL) {
847                 printk("isapnp: device '%s' order %i not found\n", value, idx);
848                 return 1;
849         }
850         isapnp_device(isapnp_info_device->devfn);
851         return 0;
852 }
853 
854 static int isapnp_autoconfigure(void)
855 {
856         if (isapnp_info_device == NULL) {
857                 printk("isapnp: device is not set\n");
858                 return 0;
859         }
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         return 0;
871 }
872 
873 static int isapnp_set_port(char *line)
874 {
875         int idx, port;
876         char index[16], value[32];
877 
878         line = isapnp_get_str(index, line, sizeof(index));
879         isapnp_get_str(value, line, sizeof(value));
880         idx = simple_strtoul(index, NULL, 0);
881         port = simple_strtoul(value, NULL, 0);
882         if (idx < 0 || idx > 7) {
883                 printk("isapnp: wrong port index %i\n", idx);
884                 return 1;
885         }
886         if (port < 0 || port > 0xffff) {
887                 printk("isapnp: wrong port value 0x%x\n", port);
888                 return 1;
889         }
890         isapnp_write_word(ISAPNP_CFG_PORT + (idx << 1), port);
891         if (!isapnp_info_device->resource[idx].flags)
892                 return 0;
893         if (isapnp_info_device->resource[idx].flags & IORESOURCE_AUTO) {
894                 isapnp_info_device->resource[idx].start = port;
895                 isapnp_info_device->resource[idx].end += port - 1;
896                 isapnp_info_device->resource[idx].flags &= ~IORESOURCE_AUTO;
897         } else {
898                 isapnp_info_device->resource[idx].end -= isapnp_info_device->resource[idx].start;
899                 isapnp_info_device->resource[idx].start = port;
900                 isapnp_info_device->resource[idx].end += port;
901         }
902         return 0;
903 }
904 
905 static void isapnp_set_irqresource(struct resource *res, int irq)
906 {
907         res->start = res->end = irq;
908         res->flags = IORESOURCE_IRQ;
909 }
910  
911 static int isapnp_set_irq(char *line)
912 {
913         int idx, irq;
914         char index[16], value[32];
915 
916         line = isapnp_get_str(index, line, sizeof(index));
917         isapnp_get_str(value, line, sizeof(value));
918         idx = simple_strtoul(index, NULL, 0);
919         irq = simple_strtoul(value, NULL, 0);
920         if (idx < 0 || idx > 1) {
921                 printk("isapnp: wrong IRQ index %i\n", idx);
922                 return 1;
923         }
924         if (irq == 2)
925                 irq = 9;
926         if (irq < 0 || irq > 15) {
927                 printk("isapnp: wrong IRQ value %i\n", irq);
928                 return 1;
929         }
930         isapnp_write_byte(ISAPNP_CFG_IRQ + (idx << 1), irq);
931         isapnp_set_irqresource(isapnp_info_device->irq_resource + idx, irq);
932         return 0;
933 }
934  
935 static void isapnp_set_dmaresource(struct resource *res, int dma)
936 {
937         res->start = res->end = dma;
938         res->flags = IORESOURCE_DMA;
939 }
940  
941 static int isapnp_set_dma(char *line)
942 {
943         int idx, dma;
944         char index[16], value[32];
945 
946         line = isapnp_get_str(index, line, sizeof(index));
947         isapnp_get_str(value, line, sizeof(value));
948         idx = simple_strtoul(index, NULL, 0);
949         dma = simple_strtoul(value, NULL, 0);
950         if (idx < 0 || idx > 1) {
951                 printk("isapnp: wrong DMA index %i\n", idx);
952                 return 1;
953         }
954         if (dma < 0 || dma > 7) {
955                 printk("isapnp: wrong DMA value %i\n", dma);
956                 return 1;
957         }
958         isapnp_write_byte(ISAPNP_CFG_DMA + idx, dma);
959         isapnp_set_dmaresource(isapnp_info_device->dma_resource + idx, dma);
960         return 0;
961 }
962  
963 static int isapnp_set_mem(char *line)
964 {
965         int idx;
966         unsigned int mem;
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         mem = simple_strtoul(value, NULL, 0);
973         if (idx < 0 || idx > 3) {
974                 printk("isapnp: wrong memory index %i\n", idx);
975                 return 1;
976         }
977         mem >>= 8;
978         isapnp_write_word(ISAPNP_CFG_MEM + (idx<<2), mem & 0xffff);
979         if (!isapnp_info_device->resource[idx + 8].flags)
980                 return 0;
981         if (isapnp_info_device->resource[idx + 8].flags & IORESOURCE_AUTO) {
982                 isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00;
983                 isapnp_info_device->resource[idx + 8].end += (mem & ~0x00ffff00) - 1;
984                 isapnp_info_device->resource[idx + 8].flags &= ~IORESOURCE_AUTO;
985         } else {
986                 isapnp_info_device->resource[idx + 8].end -= isapnp_info_device->resource[idx + 8].start;
987                 isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00;
988                 isapnp_info_device->resource[idx + 8].end += mem & ~0x00ffff00;
989         }
990         return 0;
991 }
992  
993 static int isapnp_poke(char *line, int what)
994 {
995         int reg;
996         unsigned int val;
997         char index[16], value[32];
998 
999         line = isapnp_get_str(index, line, sizeof(index));
1000         isapnp_get_str(value, line, sizeof(value));
1001         reg = simple_strtoul(index, NULL, 0);
1002         val = simple_strtoul(value, NULL, 0);
1003         if (reg < 0 || reg > 127) {
1004                 printk("isapnp: wrong register %i\n", reg);
1005                 return 1;
1006         }
1007         switch (what) {
1008         case 1:
1009                 isapnp_write_word(reg, val);
1010                 break;
1011         case 2:
1012                 isapnp_write_dword(reg, val);
1013                 break;
1014         default:
1015                 isapnp_write_byte(reg, val);
1016                 break;
1017         }
1018         return 0;
1019 }
1020  
1021 static int isapnp_decode_line(char *line)
1022 {
1023         char cmd[32];
1024 
1025         line = isapnp_get_str(cmd, line, sizeof(cmd));
1026         if (!strcmp(cmd, "card"))
1027                 return isapnp_set_card(line);
1028         if (!strcmp(cmd, "csn"))
1029                 return isapnp_select_csn(line);
1030         if (!isapnp_info_card) {
1031                 printk("isapnp: card is not selected\n");
1032                 return 1;
1033         }
1034         if (!strncmp(cmd, "dev", 3))
1035                 return isapnp_set_device(line);
1036         if (!isapnp_info_device) {
1037                 printk("isapnp: device is not selected\n");
1038                 return 1;
1039         }
1040         if (!strncmp(cmd, "auto", 4))
1041                 return isapnp_autoconfigure();
1042         if (!strncmp(cmd, "act", 3)) {
1043                 isapnp_activate(isapnp_info_device->devfn);
1044                 isapnp_info_device->active = 1;
1045                 return 0;
1046         }
1047         if (!strncmp(cmd, "deact", 5)) {
1048                 isapnp_deactivate(isapnp_info_device->devfn);
1049                 isapnp_info_device->active = 0;
1050                 return 0;
1051         }
1052         if (!strcmp(cmd, "port"))
1053                 return isapnp_set_port(line);
1054         if (!strcmp(cmd, "irq"))
1055                 return isapnp_set_irq(line);
1056         if (!strcmp(cmd, "dma"))
1057                 return isapnp_set_dma(line);
1058         if (!strncmp(cmd, "mem", 3))
1059                 return isapnp_set_mem(line);
1060         if (!strcmp(cmd, "poke"))
1061                 return isapnp_poke(line, 0);
1062         if (!strcmp(cmd, "pokew"))
1063                 return isapnp_poke(line, 1);
1064         if (!strcmp(cmd, "poked"))
1065                 return isapnp_poke(line, 2);
1066         printk("isapnp: wrong command '%s'\n", cmd);
1067         return 1;
1068 }
1069 
1070 /*
1071  *  Main write routine
1072  */
1073 
1074 static void isapnp_info_write(isapnp_info_buffer_t *buffer)
1075 {
1076         int c, idx, idx1 = 0;
1077         char line[128];
1078 
1079         if (buffer->size <= 0)
1080                 return;
1081         isapnp_info_card = NULL;
1082         isapnp_info_device = NULL;
1083         for (idx = 0; idx < buffer->size; idx++) {
1084                 c = buffer->buffer[idx];
1085                 if (c == '\n') {
1086                         line[idx1] = '\0';
1087                         if (line[0] != '#') {
1088                                 if (isapnp_decode_line(line))
1089                                         goto __end;
1090                         }
1091                         idx1 = 0;
1092                         continue;
1093                 }
1094                 if (idx1 >= sizeof(line)-1) {
1095                         printk("isapnp: line too long, aborting\n");
1096                         return;
1097                 }
1098                 line[idx1++] = c;
1099         }
1100       __end:
1101         if (isapnp_info_card)
1102                 isapnp_cfg_end();
1103 }
1104 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.