📄 isapnp_proc.c
字号:
/* * ISA Plug & Play support * Copyright (c) by Jaroslav Kysela <perex@suse.cz> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#define __NO_VERSION__#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/poll.h>#include <linux/vmalloc.h>#include <asm/uaccess.h>#include <linux/smp_lock.h>#include <linux/isapnp.h>struct isapnp_info_buffer { char *buffer; /* pointer to begin of buffer */ char *curr; /* current position in buffer */ unsigned long size; /* current size */ unsigned long len; /* total length of buffer */ int stop; /* stop flag */ int error; /* error code */};typedef struct isapnp_info_buffer isapnp_info_buffer_t;static struct proc_dir_entry *isapnp_proc_entry = NULL;static struct proc_dir_entry *isapnp_proc_bus_dir = NULL;static struct proc_dir_entry *isapnp_proc_devices_entry = NULL;static void isapnp_info_read(isapnp_info_buffer_t *buffer);static void isapnp_info_write(isapnp_info_buffer_t *buffer);int isapnp_printf(isapnp_info_buffer_t * buffer, char *fmt,...){ va_list args; int res; char sbuffer[512]; if (buffer->stop || buffer->error) return 0; va_start(args, fmt); res = vsprintf(sbuffer, fmt, args); va_end(args); if (buffer->size + res >= buffer->len) { buffer->stop = 1; return 0; } strcpy(buffer->curr, sbuffer); buffer->curr += res; buffer->size += res; return res;}static void isapnp_devid(char *str, unsigned short vendor, unsigned short device){ sprintf(str, "%c%c%c%x%x%x%x", 'A' + ((vendor >> 2) & 0x3f) - 1, 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, 'A' + ((vendor >> 8) & 0x1f) - 1, (device >> 4) & 0x0f, device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f);}static loff_t isapnp_info_entry_lseek(struct file *file, loff_t offset, int orig){ switch (orig) { case 0: /* SEEK_SET */ file->f_pos = offset; return file->f_pos; case 1: /* SEEK_CUR */ file->f_pos += offset; return file->f_pos; case 2: /* SEEK_END */ default: return -EINVAL; } return -ENXIO;}static ssize_t isapnp_info_entry_read(struct file *file, char *buffer, size_t count, loff_t * offset){ isapnp_info_buffer_t *buf; long size = 0, size1; int mode; mode = file->f_flags & O_ACCMODE; if (mode != O_RDONLY) return -EINVAL; buf = (isapnp_info_buffer_t *) file->private_data; if (!buf) return -EIO; if (file->f_pos >= buf->size) return 0; size = buf->size < count ? buf->size : count; size1 = buf->size - file->f_pos; if (size1 < size) size = size1; if (copy_to_user(buffer, buf->buffer + file->f_pos, size)) return -EFAULT; file->f_pos += size; return size;}static ssize_t isapnp_info_entry_write(struct file *file, const char *buffer, size_t count, loff_t * offset){ isapnp_info_buffer_t *buf; long size = 0, size1; int mode; mode = file->f_flags & O_ACCMODE; if (mode != O_WRONLY) return -EINVAL; buf = (isapnp_info_buffer_t *) file->private_data; if (!buf) return -EIO; if (file->f_pos < 0) return -EINVAL; if (file->f_pos >= buf->len) return -ENOMEM; size = buf->len < count ? buf->len : count; size1 = buf->len - file->f_pos; if (size1 < size) size = size1; if (copy_from_user(buf->buffer + file->f_pos, buffer, size)) return -EFAULT; if (buf->size < file->f_pos + size) buf->size = file->f_pos + size; file->f_pos += size; return size;}static int isapnp_info_entry_open(struct inode *inode, struct file *file){ isapnp_info_buffer_t *buffer; int mode; mode = file->f_flags & O_ACCMODE; if (mode != O_RDONLY && mode != O_WRONLY) return -EINVAL; buffer = (isapnp_info_buffer_t *) isapnp_alloc(sizeof(isapnp_info_buffer_t)); if (!buffer) return -ENOMEM; buffer->len = 4 * PAGE_SIZE; buffer->buffer = vmalloc(buffer->len); if (!buffer->buffer) { kfree(buffer); return -ENOMEM; } lock_kernel(); buffer->curr = buffer->buffer; file->private_data = buffer; if (mode == O_RDONLY) isapnp_info_read(buffer); unlock_kernel(); return 0;}static int isapnp_info_entry_release(struct inode *inode, struct file *file){ isapnp_info_buffer_t *buffer; int mode; if ((buffer = (isapnp_info_buffer_t *) file->private_data) == NULL) return -EINVAL; mode = file->f_flags & O_ACCMODE; lock_kernel(); if (mode == O_WRONLY) isapnp_info_write(buffer); vfree(buffer->buffer); kfree(buffer); unlock_kernel(); return 0;}static unsigned int isapnp_info_entry_poll(struct file *file, poll_table * wait){ if (!file->private_data) return 0; return POLLIN | POLLRDNORM;}static struct file_operations isapnp_info_entry_operations ={ llseek: isapnp_info_entry_lseek, read: isapnp_info_entry_read, write: isapnp_info_entry_write, poll: isapnp_info_entry_poll, open: isapnp_info_entry_open, release: isapnp_info_entry_release,};static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence){ loff_t new; switch (whence) { case 0: new = off; break; case 1: new = file->f_pos + off; break; case 2: new = 256 + off; break; default: return -EINVAL; } if (new < 0 || new > 256) return -EINVAL; return (file->f_pos = new);}static ssize_t isapnp_proc_bus_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos){ struct inode *ino = file->f_dentry->d_inode; struct proc_dir_entry *dp = ino->u.generic_ip; struct pci_dev *dev = dp->data; int pos = *ppos; int cnt, size = 256; if (pos >= size) return 0; if (nbytes >= size) nbytes = size; if (pos + nbytes > size) nbytes = size - pos; cnt = nbytes; if (!access_ok(VERIFY_WRITE, buf, cnt)) return -EINVAL; isapnp_cfg_begin(dev->bus->number, dev->devfn); for ( ; pos < 256 && cnt > 0; pos++, buf++, cnt--) { unsigned char val; val = isapnp_read_byte(pos); __put_user(val, buf); } isapnp_cfg_end(); *ppos = pos; return nbytes;}static struct file_operations isapnp_proc_bus_file_operations ={ llseek: isapnp_proc_bus_lseek, read: isapnp_proc_bus_read,};static int isapnp_proc_attach_device(struct pci_dev *dev){ struct pci_bus *bus = dev->bus; struct proc_dir_entry *de, *e; char name[16]; if (!(de = bus->procdir)) { sprintf(name, "%02x", bus->number); de = bus->procdir = proc_mkdir(name, isapnp_proc_bus_dir); if (!de) return -ENOMEM; } sprintf(name, "%02x", dev->devfn); e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de); if (!e) return -ENOMEM; e->proc_fops = &isapnp_proc_bus_file_operations; e->owner = THIS_MODULE; e->data = dev; e->size = 256; return 0;}#ifdef MODULEstatic int __exit isapnp_proc_detach_device(struct pci_dev *dev){ struct pci_bus *bus = dev->bus; struct proc_dir_entry *de; char name[16]; if (!(de = bus->procdir)) return -EINVAL; sprintf(name, "%02x", dev->devfn); remove_proc_entry(name, de); return 0;}static int __exit isapnp_proc_detach_bus(struct pci_bus *bus){ struct proc_dir_entry *de; char name[16]; if (!(de = bus->procdir)) return -EINVAL; sprintf(name, "%02x", bus->number); remove_proc_entry(name, isapnp_proc_bus_dir); return 0;}#endifstatic int isapnp_proc_read_devices(char *buf, char **start, off_t pos, int count){ struct pci_dev *dev; off_t at = 0; int len, cnt, i; cnt = 0; isapnp_for_each_dev(dev) { char bus_id[8], device_id[8]; isapnp_devid(bus_id, dev->bus->vendor, dev->bus->device); isapnp_devid(device_id, dev->vendor, dev->device); len = sprintf(buf, "%02x%02x\t%s%s\t", dev->bus->number, dev->devfn, bus_id, device_id); isapnp_cfg_begin(dev->bus->number, dev->devfn); len += sprintf(buf+len, "%02x", isapnp_read_byte(ISAPNP_CFG_ACTIVATE)); for (i = 0; i < 8; i++) len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_PORT + (i << 1))); for (i = 0; i < 2; i++) len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1))); for (i = 0; i < 2; i++) len += sprintf(buf+len, "%04x", isapnp_read_word(ISAPNP_CFG_DMA + i)); for (i = 0; i < 4; i++) len += sprintf(buf+len, "%08x", isapnp_read_dword(ISAPNP_CFG_MEM + (i << 3))); isapnp_cfg_end(); buf[len++] = '\n'; at += len; if (at >= pos) { if (!*start) { *start = buf + (pos - (at - len)); cnt = at - pos; } else cnt += len; buf += len; } } return (count > cnt) ? cnt : count;}int __init isapnp_proc_init(void){ struct proc_dir_entry *p; struct pci_dev *dev; isapnp_proc_entry = NULL; p = create_proc_entry("isapnp", S_IFREG | S_IRUGO | S_IWUSR, &proc_root); if (p) { p->proc_fops = &isapnp_info_entry_operations; p->owner = THIS_MODULE; } isapnp_proc_entry = p; isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus); isapnp_proc_devices_entry = create_proc_info_entry("devices", 0, isapnp_proc_bus_dir, isapnp_proc_read_devices); isapnp_for_each_dev(dev) { isapnp_proc_attach_device(dev); } return 0;}#ifdef MODULEint __exit isapnp_proc_done(void){ struct pci_dev *dev; struct pci_bus *card; isapnp_for_each_dev(dev) { isapnp_proc_detach_device(dev); } isapnp_for_each_card(card) { isapnp_proc_detach_bus(card); } if (isapnp_proc_devices_entry) remove_proc_entry("devices", isapnp_proc_devices_entry); if (isapnp_proc_bus_dir) remove_proc_entry("isapnp", proc_bus); if (isapnp_proc_entry) remove_proc_entry("isapnp", &proc_root); return 0;}#endif /* MODULE *//* * */static void isapnp_print_devid(isapnp_info_buffer_t *buffer, unsigned short vendor, unsigned short device){ char tmp[8]; isapnp_devid(tmp, vendor, device); isapnp_printf(buffer, tmp);}static void isapnp_print_compatible(isapnp_info_buffer_t *buffer, struct pci_dev *dev){ int idx; for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++) { if (dev->vendor_compatible[idx] == 0) continue; isapnp_printf(buffer, " Compatible device "); isapnp_print_devid(buffer, dev->vendor_compatible[idx], dev->device_compatible[idx]); isapnp_printf(buffer, "\n"); }}static void isapnp_print_port(isapnp_info_buffer_t *buffer, char *space, struct isapnp_port *port){ isapnp_printf(buffer, "%sPort 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n", space, port->min, port->max, port->align ? (port->align-1) : 0, port->size, port->flags & ISAPNP_PORT_FLAG_16BITADDR ? 16 : 10);}static void isapnp_print_irq(isapnp_info_buffer_t *buffer, char *space, struct isapnp_irq *irq){ int first = 1, i; isapnp_printf(buffer, "%sIRQ ", space); for (i = 0; i < 16; i++) if (irq->map & (1<<i)) { if (!first) { isapnp_printf(buffer, ","); } else { first = 0; } if (i == 2 || i == 9) isapnp_printf(buffer, "2/9"); else isapnp_printf(buffer, "%i", i); } if (!irq->map) isapnp_printf(buffer, "<none>"); if (irq->flags & IORESOURCE_IRQ_HIGHEDGE) isapnp_printf(buffer, " High-Edge"); if (irq->flags & IORESOURCE_IRQ_LOWEDGE) isapnp_printf(buffer, " Low-Edge"); if (irq->flags & IORESOURCE_IRQ_HIGHLEVEL) isapnp_printf(buffer, " High-Level"); if (irq->flags & IORESOURCE_IRQ_LOWLEVEL) isapnp_printf(buffer, " Low-Level"); isapnp_printf(buffer, "\n");}static void isapnp_print_dma(isapnp_info_buffer_t *buffer, char *space, struct isapnp_dma *dma){ int first = 1, i; char *s; isapnp_printf(buffer, "%sDMA ", space); for (i = 0; i < 8; i++) if (dma->map & (1<<i)) { if (!first) { isapnp_printf(buffer, ","); } else { first = 0; } isapnp_printf(buffer, "%i", i); } if (!dma->map) isapnp_printf(buffer, "<none>"); switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) { case IORESOURCE_DMA_8BIT: s = "8-bit"; break; case IORESOURCE_DMA_8AND16BIT: s = "8-bit&16-bit"; break; default: s = "16-bit"; } isapnp_printf(buffer, " %s", s); if (dma->flags & IORESOURCE_DMA_MASTER) isapnp_printf(buffer, " master"); if (dma->flags & IORESOURCE_DMA_BYTE) isapnp_printf(buffer, " byte-count"); if (dma->flags & IORESOURCE_DMA_WORD) isapnp_printf(buffer, " word-count"); switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) { case IORESOURCE_DMA_TYPEA: s = "type-A"; break; case IORESOURCE_DMA_TYPEB: s = "type-B"; break; case IORESOURCE_DMA_TYPEF: s = "type-F"; break; default: s = "compatible"; break; } isapnp_printf(buffer, " %s\n", s);}static void isapnp_print_mem(isapnp_info_buffer_t *buffer, char *space, struct isapnp_mem *mem){ char *s; isapnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x", space, mem->min, mem->max, mem->align, mem->size); if (mem->flags & IORESOURCE_MEM_WRITEABLE) isapnp_printf(buffer, ", writeable"); if (mem->flags & IORESOURCE_MEM_CACHEABLE) isapnp_printf(buffer, ", cacheable"); if (mem->flags & IORESOURCE_MEM_RANGELENGTH) isapnp_printf(buffer, ", range-length"); if (mem->flags & IORESOURCE_MEM_SHADOWABLE) isapnp_printf(buffer, ", shadowable"); if (mem->flags & IORESOURCE_MEM_EXPANSIONROM) isapnp_printf(buffer, ", expansion ROM"); switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) { case IORESOURCE_MEM_8BIT: s = "8-bit"; break; case IORESOURCE_MEM_8AND16BIT: s = "8-bit&16-bit"; break; default: s = "16-bit"; } isapnp_printf(buffer, ", %s\n", s);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -