PCI device driver file operations question



In a previous entry, I wrote about how I used a userspace C program to
read and write 32-bit binary data from/to custom PCI device memory by
opening /dev/mem and mmaping the memory range that I want. This program
worked well.

To try something similar, I wrote a PCI device driver and a userspace
program. The PCI device driver contains file operations calls. The PCI
device driver contains the following file operation functions:

int test_fopsopen(struct inode *inode, struct file *file){
return 0;
}

int test_fopsrelease(struct inode *inode, struct file *file){
return 0;
}

ssize_t test_fopsread(struct file *file, char *buf, size_t count,
loff_t *ppos) {
u32 readData;
char* region0;
int offset = 0;
u32 bar0;
unsigned int barLen;

struct pci_dev *dev;
dev = pci_get_device(TEST_VENDORID, TEST_DEVICEID, NULL);
if (dev) {
pci_request_region(dev, 0, "testdriver");
bar0 = pci_resource_start(dev, 0);
barLen = pci_resource_len(dev, 0);
region0 = ioremap_nocache(bar0, barLen);

readData = readl(region0+offset);
iounmap(region0);
pci_dev_put(dev);

if (copy_to_user(buf, &readData, sizeof(u32))) return -EFAULT;

return 0;
}
else {
printk(KERN_ALERT "Error in reading data at BA0\n");
return 1;
}
}

ssize_t test_fopswrite(struct file *file, char *buf, size_t count,
loff_t *ppos) {
u32 writeData;
char* region0;
int offset = 0;
u32 bar0;
unsigned int barLen;

struct pci_dev *dev;
dev = pci_get_device(TEST_VENDORID, TEST_DEVICEID, NULL);
if (dev) {
pci_request_region(dev, 0, "testdriver");
bar0 = pci_resource_start(dev, 0);
barLen = pci_resource_len(dev, 0);
region0 = ioremap_nocache(bar0, barLen);

if (copy_from_user(&writeData, buf, sizeof(writeData))) return
-EFAULT;
writel(wroteData, region0+offset);
iounmap(region0);
pci_dev_put(dev);
return 0;
}
else {
printk(KERN_ALERT "ERROR in writing data at BA0\n");
return 1;
}
}

where TEST_VENDORID and TEST_DEVICEID are defined by the Vendor ID and
Device ID of the PCI device. My user program is a simple read test:

int main(){
int fd, len;
char c[32];

fd = open("/dev/test", O_RDWR);
if (fd == -1) {
printf("Error in opening /dev/test\n");
return 1;
}

len = read(fd, c, 32);
printf("Result: %s", c);

close(fd);
}

Both the user program and the device driver compiled with no errors.

Some questions:

1) I went ahead and "mknod /dev/test c XXX 0" where XXX is the PCI
device major number. I also "chmod 666 /dev/test" so that anyone can
access it. After I insmod the kernel module, I went ahead to run the
user program. The user program gave me the following error: Error in
opening /dev/test. What caused the error to occur?

2) How does the functions in the device driver and the user program
look? Are there any improvements that can be made?

3) Eventually, I want to be able to read and write to different offsets
from base address 0. How can I send the offset number that I want from
userspace?

4) If I want the device driver to load automatically from bootup, how
do I do that? What script do I need to edit?

.



Relevant Pages