syscall.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. #include <linux/sched.h>
  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. asmlinkage long
  17. sys_pciconfig_read(unsigned long bus, unsigned long dfn,
  18. unsigned long off, unsigned long len,
  19. void __user *buf)
  20. {
  21. struct pci_dev *dev;
  22. u8 byte;
  23. u16 word;
  24. u32 dword;
  25. long err, cfg_ret;
  26. err = -EPERM;
  27. if (!capable(CAP_SYS_ADMIN))
  28. goto error;
  29. err = -ENODEV;
  30. dev = pci_find_slot(bus, dfn);
  31. if (!dev)
  32. goto error;
  33. lock_kernel();
  34. switch (len) {
  35. case 1:
  36. cfg_ret = pci_user_read_config_byte(dev, off, &byte);
  37. break;
  38. case 2:
  39. cfg_ret = pci_user_read_config_word(dev, off, &word);
  40. break;
  41. case 4:
  42. cfg_ret = pci_user_read_config_dword(dev, off, &dword);
  43. break;
  44. default:
  45. err = -EINVAL;
  46. unlock_kernel();
  47. goto error;
  48. };
  49. unlock_kernel();
  50. err = -EIO;
  51. if (cfg_ret != PCIBIOS_SUCCESSFUL)
  52. goto error;
  53. switch (len) {
  54. case 1:
  55. err = put_user(byte, (unsigned char __user *)buf);
  56. break;
  57. case 2:
  58. err = put_user(word, (unsigned short __user *)buf);
  59. break;
  60. case 4:
  61. err = put_user(dword, (unsigned int __user *)buf);
  62. break;
  63. };
  64. return err;
  65. error:
  66. /* ??? XFree86 doesn't even check the return value. They
  67. just look for 0xffffffff in the output, since that's what
  68. they get instead of a machine check on x86. */
  69. switch (len) {
  70. case 1:
  71. put_user(-1, (unsigned char __user *)buf);
  72. break;
  73. case 2:
  74. put_user(-1, (unsigned short __user *)buf);
  75. break;
  76. case 4:
  77. put_user(-1, (unsigned int __user *)buf);
  78. break;
  79. };
  80. return err;
  81. }
  82. asmlinkage long
  83. sys_pciconfig_write(unsigned long bus, unsigned long dfn,
  84. unsigned long off, unsigned long len,
  85. void __user *buf)
  86. {
  87. struct pci_dev *dev;
  88. u8 byte;
  89. u16 word;
  90. u32 dword;
  91. int err = 0;
  92. if (!capable(CAP_SYS_ADMIN))
  93. return -EPERM;
  94. dev = pci_find_slot(bus, dfn);
  95. if (!dev)
  96. return -ENODEV;
  97. lock_kernel();
  98. switch(len) {
  99. case 1:
  100. err = get_user(byte, (u8 __user *)buf);
  101. if (err)
  102. break;
  103. err = pci_user_write_config_byte(dev, off, byte);
  104. if (err != PCIBIOS_SUCCESSFUL)
  105. err = -EIO;
  106. break;
  107. case 2:
  108. err = get_user(word, (u16 __user *)buf);
  109. if (err)
  110. break;
  111. err = pci_user_write_config_word(dev, off, word);
  112. if (err != PCIBIOS_SUCCESSFUL)
  113. err = -EIO;
  114. break;
  115. case 4:
  116. err = get_user(dword, (u32 __user *)buf);
  117. if (err)
  118. break;
  119. err = pci_user_write_config_dword(dev, off, dword);
  120. if (err != PCIBIOS_SUCCESSFUL)
  121. err = -EIO;
  122. break;
  123. default:
  124. err = -EINVAL;
  125. break;
  126. };
  127. unlock_kernel();
  128. return err;
  129. }