Blame |
Last modification |
View Log
| RSS feed
/*
* drivers/pci/pci-sysfs.c
*
* (C) Copyright 2002 Greg Kroah-Hartman
* (C) Copyright 2002 IBM Corp.
* (C) Copyright 2003 Matthew Wilcox
* (C) Copyright 2003 Hewlett-Packard
*
* File attributes for PCI devices
*
* Modeled after usb's driverfs.c
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/stat.h>
#include "pci.h"
/* show configuration fields */
#define pci_config_attr(field, format_string) \
static ssize_t \
show_##field (struct device *dev, char *buf) \
{ \
struct pci_dev *pdev; \
\
pdev = to_pci_dev (dev); \
return sprintf (buf, format_string, pdev->field); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
pci_config_attr
(vendor
, "0x%04x\n");
pci_config_attr
(device
, "0x%04x\n");
pci_config_attr
(subsystem_vendor
, "0x%04x\n");
pci_config_attr
(subsystem_device
, "0x%04x\n");
pci_config_attr
(class
, "0x%06x\n");
pci_config_attr
(irq
, "%u\n");
/* show resources */
static ssize_t
pci_show_resources
(struct device
* dev
, char * buf
)
{
struct pci_dev
* pci_dev
= to_pci_dev
(dev
);
char * str
= buf
;
int i
;
int max
= 7;
if (pci_dev
->subordinate
)
max
= DEVICE_COUNT_RESOURCE
;
for (i
= 0; i
< max
; i
++) {
str
+= sprintf(str
,"0x%016lx 0x%016lx 0x%016lx\n",
pci_resource_start
(pci_dev
,i
),
pci_resource_end
(pci_dev
,i
),
pci_resource_flags
(pci_dev
,i
));
}
return (str
- buf
);
}
static DEVICE_ATTR
(resource
,S_IRUGO
,pci_show_resources
,NULL
);
static ssize_t
pci_read_config
(struct kobject
*kobj
, char *buf
, loff_t off
, size_t count
)
{
struct pci_dev
*dev
= to_pci_dev
(container_of
(kobj
,struct device
,kobj
));
unsigned int size
= 64;
loff_t init_off
= off
;
/* Several chips lock up trying to read undefined config space */
if (capable
(CAP_SYS_ADMIN
)) {
size
= 256;
} else if (dev
->hdr_type
== PCI_HEADER_TYPE_CARDBUS
) {
size
= 128;
}
if (off
> size
)
return 0;
if (off
+ count
> size
) {
size
-= off
;
count
= size
;
} else {
size
= count
;
}
while (off
& 3) {
unsigned char val
;
pci_read_config_byte
(dev
, off
, &val
);
buf
[off
- init_off
] = val
;
off
++;
if (--size
== 0)
break;
}
while (size
> 3) {
unsigned int val
;
pci_read_config_dword
(dev
, off
, &val
);
buf
[off
- init_off
] = val
& 0xff;
buf
[off
- init_off
+ 1] = (val
>> 8) & 0xff;
buf
[off
- init_off
+ 2] = (val
>> 16) & 0xff;
buf
[off
- init_off
+ 3] = (val
>> 24) & 0xff;
off
+= 4;
size
-= 4;
}
while (size
> 0) {
unsigned char val
;
pci_read_config_byte
(dev
, off
, &val
);
buf
[off
- init_off
] = val
;
off
++;
--size
;
}
return count
;
}
static ssize_t
pci_write_config
(struct kobject
*kobj
, char *buf
, loff_t off
, size_t count
)
{
struct pci_dev
*dev
= to_pci_dev
(container_of
(kobj
,struct device
,kobj
));
unsigned int size
= count
;
loff_t init_off
= off
;
if (off
> 256)
return 0;
if (off
+ count
> 256) {
size
= 256 - off
;
count
= size
;
}
while (off
& 3) {
pci_write_config_byte
(dev
, off
, buf
[off
- init_off
]);
off
++;
if (--size
== 0)
break;
}
while (size
> 3) {
unsigned int val
= buf
[off
- init_off
];
val
|= (unsigned int) buf
[off
- init_off
+ 1] << 8;
val
|= (unsigned int) buf
[off
- init_off
+ 2] << 16;
val
|= (unsigned int) buf
[off
- init_off
+ 3] << 24;
pci_write_config_dword
(dev
, off
, val
);
off
+= 4;
size
-= 4;
}
while (size
> 0) {
pci_write_config_byte
(dev
, off
, buf
[off
- init_off
]);
off
++;
--size
;
}
return count
;
}
static struct bin_attribute pci_config_attr
= {
.
attr = {
.
name = "config",
.
mode = S_IRUGO
| S_IWUSR
,
},
.
size = 256,
.
read = pci_read_config
,
.
write = pci_write_config
,
};
void pci_create_sysfs_dev_files
(struct pci_dev
*pdev
)
{
struct device
*dev
= &pdev
->dev
;
/* current configuration's attributes */
device_create_file
(dev
, &dev_attr_vendor
);
device_create_file
(dev
, &dev_attr_device
);
device_create_file
(dev
, &dev_attr_subsystem_vendor
);
device_create_file
(dev
, &dev_attr_subsystem_device
);
device_create_file
(dev
, &dev_attr_class
);
device_create_file
(dev
, &dev_attr_irq
);
device_create_file
(dev
, &dev_attr_resource
);
sysfs_create_bin_file
(&dev
->kobj
, &pci_config_attr
);
}