2005-04-17 02:20:36 +04:00
/*
* pci_syscall . c
*
* For architectures where we want to allow direct access
* to the PCI config stuff - it would probably be preferable
* on PCs too , but there people just do it by hand with the
* magic northbridge registers . .
*/
# include <linux/errno.h>
# include <linux/pci.h>
# include <linux/syscalls.h>
# include <asm/uaccess.h>
2005-09-27 12:21:55 +04:00
# include "pci.h"
2005-04-17 02:20:36 +04:00
2009-01-14 16:14:28 +03:00
SYSCALL_DEFINE5 ( pciconfig_read , unsigned long , bus , unsigned long , dfn ,
unsigned long , off , unsigned long , len , void __user * , buf )
2005-04-17 02:20:36 +04:00
{
struct pci_dev * dev ;
u8 byte ;
u16 word ;
u32 dword ;
2007-04-23 17:57:37 +04:00
long err ;
long cfg_ret ;
2005-04-17 02:20:36 +04:00
if ( ! capable ( CAP_SYS_ADMIN ) )
2007-04-23 17:57:37 +04:00
return - EPERM ;
2005-04-17 02:20:36 +04:00
err = - ENODEV ;
2007-04-23 17:57:37 +04:00
dev = pci_get_bus_and_slot ( bus , dfn ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev )
goto error ;
switch ( len ) {
case 1 :
2005-09-27 12:21:55 +04:00
cfg_ret = pci_user_read_config_byte ( dev , off , & byte ) ;
2005-04-17 02:20:36 +04:00
break ;
case 2 :
2005-09-27 12:21:55 +04:00
cfg_ret = pci_user_read_config_word ( dev , off , & word ) ;
2005-04-17 02:20:36 +04:00
break ;
case 4 :
2005-09-27 12:21:55 +04:00
cfg_ret = pci_user_read_config_dword ( dev , off , & dword ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
err = - EINVAL ;
goto error ;
} ;
err = - EIO ;
if ( cfg_ret ! = PCIBIOS_SUCCESSFUL )
goto error ;
switch ( len ) {
case 1 :
err = put_user ( byte , ( unsigned char __user * ) buf ) ;
break ;
case 2 :
err = put_user ( word , ( unsigned short __user * ) buf ) ;
break ;
case 4 :
err = put_user ( dword , ( unsigned int __user * ) buf ) ;
break ;
2007-04-23 17:57:37 +04:00
}
pci_dev_put ( dev ) ;
2005-04-17 02:20:36 +04:00
return err ;
error :
/* ??? XFree86 doesn't even check the return value. They
just look for 0xffffffff in the output , since that ' s what
they get instead of a machine check on x86 . */
switch ( len ) {
case 1 :
put_user ( - 1 , ( unsigned char __user * ) buf ) ;
break ;
case 2 :
put_user ( - 1 , ( unsigned short __user * ) buf ) ;
break ;
case 4 :
put_user ( - 1 , ( unsigned int __user * ) buf ) ;
break ;
2007-04-23 17:57:37 +04:00
}
pci_dev_put ( dev ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
2009-01-14 16:14:28 +03:00
SYSCALL_DEFINE5 ( pciconfig_write , unsigned long , bus , unsigned long , dfn ,
unsigned long , off , unsigned long , len , void __user * , buf )
2005-04-17 02:20:36 +04:00
{
struct pci_dev * dev ;
u8 byte ;
u16 word ;
u32 dword ;
int err = 0 ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
2007-04-23 17:57:37 +04:00
dev = pci_get_bus_and_slot ( bus , dfn ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev )
return - ENODEV ;
switch ( len ) {
case 1 :
err = get_user ( byte , ( u8 __user * ) buf ) ;
if ( err )
break ;
2005-09-27 12:21:55 +04:00
err = pci_user_write_config_byte ( dev , off , byte ) ;
2005-04-17 02:20:36 +04:00
if ( err ! = PCIBIOS_SUCCESSFUL )
err = - EIO ;
break ;
case 2 :
err = get_user ( word , ( u16 __user * ) buf ) ;
if ( err )
break ;
2005-09-27 12:21:55 +04:00
err = pci_user_write_config_word ( dev , off , word ) ;
2005-04-17 02:20:36 +04:00
if ( err ! = PCIBIOS_SUCCESSFUL )
err = - EIO ;
break ;
case 4 :
err = get_user ( dword , ( u32 __user * ) buf ) ;
if ( err )
break ;
2005-09-27 12:21:55 +04:00
err = pci_user_write_config_dword ( dev , off , dword ) ;
2005-04-17 02:20:36 +04:00
if ( err ! = PCIBIOS_SUCCESSFUL )
err = - EIO ;
break ;
default :
err = - EINVAL ;
break ;
2007-04-23 17:57:37 +04:00
}
pci_dev_put ( dev ) ;
2005-04-17 02:20:36 +04:00
return err ;
}