home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lxapi32.zip / Linux / PCI / proc.c < prev    next >
C/C++ Source or Header  |  2002-04-26  |  13KB  |  573 lines

  1. /*
  2.  *    $Id: proc.c,v 1.2 2002/04/26 23:09:32 smilcke Exp $
  3.  *
  4.  *    Procfs interface for the PCI bus.
  5.  *
  6.  *    Copyright (c) 1997--1999 Martin Mares <mj@ucw.cz>
  7.  */
  8.  
  9. #include <linux/types.h>
  10. #include <linux/kernel.h>
  11. #include <linux/pci.h>
  12. #include <linux/proc_fs.h>
  13. #include <linux/init.h>
  14. #include <linux/seq_file.h>
  15.  
  16. #include <asm/uaccess.h>
  17. #include <asm/byteorder.h>
  18.  
  19. #define PCI_CFG_SPACE_SIZE 256
  20.  
  21. static loff_t
  22. proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
  23. {
  24.     loff_t new;
  25.  
  26.     switch (whence) {
  27.     case 0:
  28.         new = off;
  29.         break;
  30.     case 1:
  31.         new = file->f_pos + off;
  32.         break;
  33.     case 2:
  34.         new = PCI_CFG_SPACE_SIZE + off;
  35.         break;
  36.     default:
  37.         return -EINVAL;
  38.     }
  39.     if (new < 0 || new > PCI_CFG_SPACE_SIZE)
  40.         return -EINVAL;
  41.     return (file->f_pos = new);
  42. }
  43.  
  44. static ssize_t
  45. proc_bus_pci_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
  46. {
  47.     const struct inode *ino = file->f_dentry->d_inode;
  48.     const struct proc_dir_entry *dp = ino->u.generic_ip;
  49.     struct pci_dev *dev = dp->data;
  50.     unsigned int pos = *ppos;
  51.     unsigned int cnt, size;
  52.  
  53.     /*
  54.      * Normal users can read only the standardized portion of the
  55.      * configuration space as several chips lock up when trying to read
  56.      * undefined locations (think of Intel PIIX4 as a typical example).
  57.      */
  58.  
  59.     if (capable(CAP_SYS_ADMIN))
  60.         size = PCI_CFG_SPACE_SIZE;
  61.     else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
  62.         size = 128;
  63.     else
  64.         size = 64;
  65.  
  66.     if (pos >= size)
  67.         return 0;
  68.     if (nbytes >= size)
  69.         nbytes = size;
  70.     if (pos + nbytes > size)
  71.         nbytes = size - pos;
  72.     cnt = nbytes;
  73.  
  74.     if (!access_ok(VERIFY_WRITE, buf, cnt))
  75.         return -EINVAL;
  76.  
  77.     if ((pos & 1) && cnt) {
  78.         unsigned char val;
  79.         pci_read_config_byte(dev, pos, &val);
  80.         __put_user(val, buf);
  81.         buf++;
  82.         pos++;
  83.         cnt--;
  84.     }
  85.  
  86.     if ((pos & 3) && cnt > 2) {
  87.         unsigned short val;
  88.         pci_read_config_word(dev, pos, &val);
  89.         __put_user(cpu_to_le16(val), (unsigned short *) buf);
  90.         buf += 2;
  91.         pos += 2;
  92.         cnt -= 2;
  93.     }
  94.  
  95.     while (cnt >= 4) {
  96.         unsigned int val;
  97.         pci_read_config_dword(dev, pos, &val);
  98.         __put_user(cpu_to_le32(val), (unsigned int *) buf);
  99.         buf += 4;
  100.         pos += 4;
  101.         cnt -= 4;
  102.     }
  103.  
  104.     if (cnt >= 2) {
  105.         unsigned short val;
  106.         pci_read_config_word(dev, pos, &val);
  107.         __put_user(cpu_to_le16(val), (unsigned short *) buf);
  108.         buf += 2;
  109.         pos += 2;
  110.         cnt -= 2;
  111.     }
  112.  
  113.     if (cnt) {
  114.         unsigned char val;
  115.         pci_read_config_byte(dev, pos, &val);
  116.         __put_user(val, buf);
  117.         buf++;
  118.         pos++;
  119.         cnt--;
  120.     }
  121.  
  122.     *ppos = pos;
  123.     return nbytes;
  124. }
  125.  
  126. static ssize_t
  127. proc_bus_pci_write(struct file *file, const char *buf, size_t nbytes, loff_t *ppos)
  128. {
  129.     const struct inode *ino = file->f_dentry->d_inode;
  130.     const struct proc_dir_entry *dp = ino->u.generic_ip;
  131.     struct pci_dev *dev = dp->data;
  132.     int pos = *ppos;
  133.     int cnt;
  134.  
  135.     if (pos >= PCI_CFG_SPACE_SIZE)
  136.         return 0;
  137.     if (nbytes >= PCI_CFG_SPACE_SIZE)
  138.         nbytes = PCI_CFG_SPACE_SIZE;
  139.     if (pos + nbytes > PCI_CFG_SPACE_SIZE)
  140.         nbytes = PCI_CFG_SPACE_SIZE - pos;
  141.     cnt = nbytes;
  142.  
  143.     if (!access_ok(VERIFY_READ, buf, cnt))
  144.         return -EINVAL;
  145.  
  146.     if ((pos & 1) && cnt) {
  147.         unsigned char val;
  148.         __get_user(val, buf);
  149.         pci_write_config_byte(dev, pos, val);
  150.         buf++;
  151.         pos++;
  152.         cnt--;
  153.     }
  154.  
  155.     if ((pos & 3) && cnt > 2) {
  156.         unsigned short val;
  157.         __get_user(val, (unsigned short *) buf);
  158.         pci_write_config_word(dev, pos, le16_to_cpu(val));
  159.         buf += 2;
  160.         pos += 2;
  161.         cnt -= 2;
  162.     }
  163.  
  164.     while (cnt >= 4) {
  165.         unsigned int val;
  166.         __get_user(val, (unsigned int *) buf);
  167.         pci_write_config_dword(dev, pos, le32_to_cpu(val));
  168.         buf += 4;
  169.         pos += 4;
  170.         cnt -= 4;
  171.     }
  172.  
  173.     if (cnt >= 2) {
  174.         unsigned short val;
  175.         __get_user(val, (unsigned short *) buf);
  176.         pci_write_config_word(dev, pos, le16_to_cpu(val));
  177.         buf += 2;
  178.         pos += 2;
  179.         cnt -= 2;
  180.     }
  181.  
  182.     if (cnt) {
  183.         unsigned char val;
  184.         __get_user(val, buf);
  185.         pci_write_config_byte(dev, pos, val);
  186.         buf++;
  187.         pos++;
  188.         cnt--;
  189.     }
  190.  
  191.     *ppos = pos;
  192.     return nbytes;
  193. }
  194.  
  195. struct pci_filp_private {
  196.     enum pci_mmap_state mmap_state;
  197.     int write_combine;
  198. };
  199.  
  200. static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
  201. {
  202.     const struct proc_dir_entry *dp = inode->u.generic_ip;
  203.     struct pci_dev *dev = dp->data;
  204. #ifdef HAVE_PCI_MMAP
  205.     struct pci_filp_private *fpriv = file->private_data;
  206. #endif /* HAVE_PCI_MMAP */
  207.     int ret = 0;
  208.  
  209.     switch (cmd) {
  210.     case PCIIOC_CONTROLLER:
  211.         ret = pci_controller_num(dev);
  212.         break;
  213.  
  214. #ifdef HAVE_PCI_MMAP
  215.     case PCIIOC_MMAP_IS_IO:
  216.         fpriv->mmap_state = pci_mmap_io;
  217.         break;
  218.  
  219.     case PCIIOC_MMAP_IS_MEM:
  220.         fpriv->mmap_state = pci_mmap_mem;
  221.         break;
  222.  
  223.     case PCIIOC_WRITE_COMBINE:
  224.         if (arg)
  225.             fpriv->write_combine = 1;
  226.         else
  227.             fpriv->write_combine = 0;
  228.         break;
  229.  
  230. #endif /* HAVE_PCI_MMAP */
  231.  
  232.     default:
  233.         ret = -EINVAL;
  234.         break;
  235.     };
  236.  
  237.     return ret;
  238. }
  239.  
  240. #ifdef HAVE_PCI_MMAP
  241. static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
  242. {
  243.     struct inode *inode = file->f_dentry->d_inode;
  244.     const struct proc_dir_entry *dp = inode->u.generic_ip;
  245.     struct pci_dev *dev = dp->data;
  246.     struct pci_filp_private *fpriv = file->private_data;
  247.     int ret;
  248.  
  249.     if (!capable(CAP_SYS_RAWIO))
  250.         return -EPERM;
  251.  
  252.     ret = pci_mmap_page_range(dev, vma,
  253.                   fpriv->mmap_state,
  254.                   fpriv->write_combine);
  255.     if (ret < 0)
  256.         return ret;
  257.  
  258.     return 0;
  259. }
  260.  
  261. static int proc_bus_pci_open(struct inode *inode, struct file *file)
  262. {
  263.     struct pci_filp_private *fpriv = kmalloc(sizeof(*fpriv), GFP_KERNEL);
  264.  
  265.     if (!fpriv)
  266.         return -ENOMEM;
  267.  
  268.     fpriv->mmap_state = pci_mmap_io;
  269.     fpriv->write_combine = 0;
  270.  
  271.     file->private_data = fpriv;
  272.  
  273.     return 0;
  274. }
  275.  
  276. static int proc_bus_pci_release(struct inode *inode, struct file *file)
  277. {
  278.     kfree(file->private_data);
  279.     file->private_data = NULL;
  280.  
  281.     return 0;
  282. }
  283. #endif /* HAVE_PCI_MMAP */
  284.  
  285. static struct file_operations proc_bus_pci_operations = {
  286.     llseek:        proc_bus_pci_lseek,
  287.     read:        proc_bus_pci_read,
  288.     write:        proc_bus_pci_write,
  289.     ioctl:        proc_bus_pci_ioctl,
  290. #ifdef HAVE_PCI_MMAP
  291.     open:        proc_bus_pci_open,
  292.     release:    proc_bus_pci_release,
  293.     mmap:        proc_bus_pci_mmap,
  294. #ifdef HAVE_ARCH_PCI_GET_UNMAPPED_AREA
  295.     get_unmapped_area: get_pci_unmapped_area,
  296. #endif /* HAVE_ARCH_PCI_GET_UNMAPPED_AREA */
  297. #endif /* HAVE_PCI_MMAP */
  298. };
  299.  
  300. #if BITS_PER_LONG == 32
  301. #define LONG_FORMAT "\t%08lx"
  302. #else
  303. #define LONG_FORMAT "\t%16lx"
  304. #endif
  305.  
  306. /* iterator */
  307. static void *pci_seq_start(struct seq_file *m, loff_t *pos)
  308. {
  309.     struct list_head *p = &pci_devices;
  310.     loff_t n = *pos;
  311.  
  312.     /* XXX: surely we need some locking for traversing the list? */
  313.     while (n--) {
  314.         p = p->next;
  315.         if (p == &pci_devices)
  316.             return NULL;
  317.     }
  318.     return p;
  319. }
  320. static void *pci_seq_next(struct seq_file *m, void *v, loff_t *pos)
  321. {
  322.     struct list_head *p = v;
  323.     (*pos)++;
  324.     return p->next != &pci_devices ? p->next : NULL;
  325. }
  326. static void pci_seq_stop(struct seq_file *m, void *v)
  327. {
  328.     /* release whatever locks we need */
  329. }
  330.  
  331. static int show_device(struct seq_file *m, void *v)
  332. {
  333.     struct list_head *p = v;
  334.     const struct pci_dev *dev;
  335.     const struct pci_driver *drv;
  336.     int i;
  337.  
  338.     if (p == &pci_devices)
  339.         return 0;
  340.  
  341.     dev = pci_dev_g(p);
  342.     drv = pci_dev_driver(dev);
  343.     seq_printf(m, "%02x%02x\t%04x%04x\t%x",
  344.             dev->bus->number,
  345.             dev->devfn,
  346.             dev->vendor,
  347.             dev->device,
  348.             dev->irq);
  349.     /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */
  350.     for(i=0; i<7; i++)
  351.         seq_printf(m, LONG_FORMAT,
  352.             dev->resource[i].start |
  353.             (dev->resource[i].flags & PCI_REGION_FLAG_MASK));
  354.     for(i=0; i<7; i++)
  355.         seq_printf(m, LONG_FORMAT,
  356.             dev->resource[i].start < dev->resource[i].end ?
  357.             dev->resource[i].end - dev->resource[i].start + 1 : 0);
  358.     seq_putc(m, '\t');
  359.     if (drv)
  360.         seq_printf(m, "%s", drv->name);
  361.     seq_putc(m, '\n');
  362.     return 0;
  363. }
  364.  
  365. static struct seq_operations proc_bus_pci_devices_op = {
  366.     start:    pci_seq_start,
  367.     next:    pci_seq_next,
  368.     stop:    pci_seq_stop,
  369.     show:    show_device
  370. };
  371.  
  372. static struct proc_dir_entry *proc_bus_pci_dir;
  373.  
  374. int pci_proc_attach_device(struct pci_dev *dev)
  375. {
  376.     struct pci_bus *bus = dev->bus;
  377.     struct proc_dir_entry *de, *e;
  378.     char name[16];
  379.  
  380.     if (!(de = bus->procdir)) {
  381.         sprintf(name, "%02x", bus->number);
  382.         de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir);
  383.         if (!de)
  384.             return -ENOMEM;
  385.     }
  386.     sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
  387.     e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, de);
  388.     if (!e)
  389.         return -ENOMEM;
  390.     e->proc_fops = &proc_bus_pci_operations;
  391.     e->data = dev;
  392.     e->size = PCI_CFG_SPACE_SIZE;
  393.     return 0;
  394. }
  395.  
  396. int pci_proc_detach_device(struct pci_dev *dev)
  397. {
  398.     struct proc_dir_entry *e;
  399.  
  400.     if ((e = dev->procent)) {
  401.         if (atomic_read(&e->count))
  402.             return -EBUSY;
  403.         remove_proc_entry(e->name, dev->bus->procdir);
  404.         dev->procent = NULL;
  405.     }
  406.     return 0;
  407. }
  408.  
  409. int pci_proc_attach_bus(struct pci_bus* bus)
  410. {
  411.     struct proc_dir_entry *de = bus->procdir;
  412.  
  413.     if (!de) {
  414.         char name[16];
  415.         sprintf(name, "%02x", bus->number);
  416.         de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir);
  417.         if (!de)
  418.             return -ENOMEM;
  419.     }
  420.     return 0;
  421. }
  422.  
  423. int pci_proc_detach_bus(struct pci_bus* bus)
  424. {
  425.     struct proc_dir_entry *de = bus->procdir;
  426.     if (de)
  427.         remove_proc_entry(de->name, proc_bus_pci_dir);
  428.     return 0;
  429. }
  430.  
  431.  
  432. /*
  433.  *  Backward compatible /proc/pci interface.
  434.  */
  435.  
  436. /*
  437.  * Convert some of the configuration space registers of the device at
  438.  * address (bus,devfn) into a string (possibly several lines each).
  439.  * The configuration string is stored starting at buf[len].  If the
  440.  * string would exceed the size of the buffer (SIZE), 0 is returned.
  441.  */
  442. static int show_dev_config(struct seq_file *m, void *v)
  443. {
  444.     struct list_head *p = v;
  445.     struct pci_dev *dev;
  446.     struct pci_driver *drv;
  447.     u32 class_rev;
  448.     unsigned char latency, min_gnt, max_lat, *class;
  449.     int reg;
  450.  
  451.     if (p == &pci_devices) {
  452.         seq_puts(m, "PCI devices found:\n");
  453.         return 0;
  454.     }
  455.  
  456.     dev = pci_dev_g(p);
  457.     drv = pci_dev_driver(dev);
  458.  
  459.     pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
  460.     pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
  461.     pci_read_config_byte (dev, PCI_MIN_GNT, &min_gnt);
  462.     pci_read_config_byte (dev, PCI_MAX_LAT, &max_lat);
  463.     seq_printf(m, "  Bus %2d, device %3d, function %2d:\n",
  464.            dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
  465.     class = pci_class_name(class_rev >> 16);
  466.     if (class)
  467.         seq_printf(m, "    %s", class);
  468.     else
  469.         seq_printf(m, "    Class %04x", class_rev >> 16);
  470.     seq_printf(m, ": %s (rev %d).\n", dev->name, class_rev & 0xff);
  471.  
  472.     if (dev->irq)
  473.         seq_printf(m, "      IRQ %d.\n", dev->irq);
  474.  
  475.     if (latency || min_gnt || max_lat) {
  476.         seq_printf(m, "      Master Capable.  ");
  477.         if (latency)
  478.             seq_printf(m, "Latency=%d.  ", latency);
  479.         else
  480.             seq_puts(m, "No bursts.  ");
  481.         if (min_gnt)
  482.             seq_printf(m, "Min Gnt=%d.", min_gnt);
  483.         if (max_lat)
  484.             seq_printf(m, "Max Lat=%d.", max_lat);
  485.         seq_putc(m, '\n');
  486.     }
  487.  
  488.     for (reg = 0; reg < 6; reg++) {
  489.         struct resource *res = dev->resource + reg;
  490.         unsigned long base, end, flags;
  491.  
  492.         base = res->start;
  493.         end = res->end;
  494.         flags = res->flags;
  495.         if (!end)
  496.             continue;
  497.  
  498.         if (flags & PCI_BASE_ADDRESS_SPACE_IO) {
  499.             seq_printf(m, "      I/O at 0x%lx [0x%lx].\n",
  500.                 base, end);
  501.         } else {
  502.             const char *pref, *type = "unknown";
  503.  
  504.             if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
  505.                 pref = "P";
  506.             else
  507.                 pref = "Non-p";
  508.             switch (flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
  509.                   case PCI_BASE_ADDRESS_MEM_TYPE_32:
  510.                 type = "32 bit"; break;
  511.                   case PCI_BASE_ADDRESS_MEM_TYPE_1M:
  512.                 type = "20 bit"; break;
  513.                   case PCI_BASE_ADDRESS_MEM_TYPE_64:
  514.                 type = "64 bit"; break;
  515.             }
  516.             seq_printf(m, "      %srefetchable %s memory at "
  517.                        "0x%lx [0x%lx].\n", pref, type,
  518.                        base,
  519.                        end);
  520.         }
  521.     }
  522.     return 0;
  523. }
  524.  
  525. static struct seq_operations proc_pci_op = {
  526.     start:    pci_seq_start,
  527.     next:    pci_seq_next,
  528.     stop:    pci_seq_stop,
  529.     show:    show_dev_config
  530. };
  531.  
  532. static int proc_bus_pci_dev_open(struct inode *inode, struct file *file)
  533. {
  534.     return seq_open(file, &proc_bus_pci_devices_op);
  535. }
  536. static struct file_operations proc_bus_pci_dev_operations = {
  537.     open:        proc_bus_pci_dev_open,
  538.     read:        seq_read,
  539.     llseek:        seq_lseek,
  540.     release:    seq_release,
  541. };
  542. static int proc_pci_open(struct inode *inode, struct file *file)
  543. {
  544.     return seq_open(file, &proc_pci_op);
  545. }
  546. static struct file_operations proc_pci_operations = {
  547.     open:        proc_pci_open,
  548.     read:        seq_read,
  549.     llseek:        seq_lseek,
  550.     release:    seq_release,
  551. };
  552.  
  553. static int __init pci_proc_init(void)
  554. {
  555.     if (pci_present()) {
  556.         struct proc_dir_entry *entry;
  557.         struct pci_dev *dev;
  558.         proc_bus_pci_dir = proc_mkdir("pci", proc_bus);
  559.         entry = create_proc_entry("devices", 0, proc_bus_pci_dir);
  560.         if (entry)
  561.             entry->proc_fops = &proc_bus_pci_dev_operations;
  562.         pci_for_each_dev(dev) {
  563.             pci_proc_attach_device(dev);
  564.         }
  565.         entry = create_proc_entry("pci", 0, NULL);
  566.         if (entry)
  567.             entry->proc_fops = &proc_pci_operations;
  568.     }
  569.     return 0;
  570. }
  571.  
  572. __initcall(pci_proc_init);
  573.