linux/drivers/pci/syscall.c
<<
>>
Prefs
   1/*
   2 *      pci_syscall.c
   3 *
   4 * For architectures where we want to allow direct access
   5 * to the PCI config stuff - it would probably be preferable
   6 * on PCs too, but there people just do it by hand with the
   7 * magic northbridge registers..
   8 */
   9
  10#include <linux/errno.h>
  11#include <linux/pci.h>
  12#include <linux/smp_lock.h>
  13#include <linux/syscalls.h>
  14#include <asm/uaccess.h>
  15#include "pci.h"
  16
  17SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn,
  18                unsigned long, off, unsigned long, len, void __user *, buf)
  19{
  20        struct pci_dev *dev;
  21        u8 byte;
  22        u16 word;
  23        u32 dword;
  24        long err;
  25        long cfg_ret;
  26
  27        if (!capable(CAP_SYS_ADMIN))
  28                return -EPERM;
  29
  30        err = -ENODEV;
  31        dev = pci_get_bus_and_slot(bus, dfn);
  32        if (!dev)
  33                goto error;
  34
  35        switch (len) {
  36        case 1:
  37                cfg_ret = pci_user_read_config_byte(dev, off, &byte);
  38                break;
  39        case 2:
  40                cfg_ret = pci_user_read_config_word(dev, off, &word);
  41                break;
  42        case 4:
  43                cfg_ret = pci_user_read_config_dword(dev, off, &dword);
  44                break;
  45        default:
  46                err = -EINVAL;
  47                goto error;
  48        };
  49
  50        err = -EIO;
  51        if (cfg_ret != PCIBIOS_SUCCESSFUL)
  52                goto error;
  53
  54        switch (len) {
  55        case 1:
  56                err = put_user(byte, (unsigned char __user *)buf);
  57                break;
  58        case 2:
  59                err = put_user(word, (unsigned short __user *)buf);
  60                break;
  61        case 4:
  62                err = put_user(dword, (unsigned int __user *)buf);
  63                break;
  64        }
  65        pci_dev_put(dev);
  66        return err;
  67
  68error:
  69        /* ??? XFree86 doesn't even check the return value.  They
  70           just look for 0xffffffff in the output, since that's what
  71           they get instead of a machine check on x86.  */
  72        switch (len) {
  73        case 1:
  74                put_user(-1, (unsigned char __user *)buf);
  75                break;
  76        case 2:
  77                put_user(-1, (unsigned short __user *)buf);
  78                break;
  79        case 4:
  80                put_user(-1, (unsigned int __user *)buf);
  81                break;
  82        }
  83        pci_dev_put(dev);
  84        return err;
  85}
  86
  87SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
  88                unsigned long, off, unsigned long, len, void __user *, buf)
  89{
  90        struct pci_dev *dev;
  91        u8 byte;
  92        u16 word;
  93        u32 dword;
  94        int err = 0;
  95
  96        if (!capable(CAP_SYS_ADMIN))
  97                return -EPERM;
  98
  99        dev = pci_get_bus_and_slot(bus, dfn);
 100        if (!dev)
 101                return -ENODEV;
 102
 103        switch(len) {
 104        case 1:
 105                err = get_user(byte, (u8 __user *)buf);
 106                if (err)
 107                        break;
 108                err = pci_user_write_config_byte(dev, off, byte);
 109                if (err != PCIBIOS_SUCCESSFUL)
 110                        err = -EIO;
 111                break;
 112
 113        case 2:
 114                err = get_user(word, (u16 __user *)buf);
 115                if (err)
 116                        break;
 117                err = pci_user_write_config_word(dev, off, word);
 118                if (err != PCIBIOS_SUCCESSFUL)
 119                        err = -EIO;
 120                break;
 121
 122        case 4:
 123                err = get_user(dword, (u32 __user *)buf);
 124                if (err)
 125                        break;
 126                err = pci_user_write_config_dword(dev, off, dword);
 127                if (err != PCIBIOS_SUCCESSFUL)
 128                        err = -EIO;
 129                break;
 130
 131        default:
 132                err = -EINVAL;
 133                break;
 134        }
 135        pci_dev_put(dev);
 136        return err;
 137}
 138