PCI device driver question
Hi everyone,
I am writing a PCI device driver. In the pci device driver, I am able
to do the following:
static int probe(struct pci_dev *dev, const struct pci_device_id *id)
{
char *region0;
u32 bar0;
unsigned int barLen0;
int barNumber0 = 0;
pci_enable_device(dev);
pci_request_region(dev, barNumber0, "driverBAR0");
bar0 = pci_resource_start (dev, barNumber0);
barLen0 = pci_resource_len(dev, barNumber0);
region0 = ioremap_nocache(bar0, barLen0);
writeb('A', region0+0x04);
iounmap(region0);
return 0;
}
Now instead of hard-coding what to write in the memory region, I want
to input a file, read the file, and write the appropriate contents to
the memory region. What are the appropriate steps to do that? It seems
as though that I cannot use the library stdio in pci device drivers. Is
there another library that contains file IO? Or do I need to create a
program in userspace that would read the file, access the pci device
driver, and call a write function?
Re: PCI device driver question
In article <1166736838.855581.113720@80g2000cwy.googlegroups.com>,
[email]elliotng.ee@gmail.com[/email] <elliotng.ee@gmail.com> wrote:
[color=blue]
>Now instead of hard-coding what to write in the memory region, I want
>to input a file, read the file, and write the appropriate contents to
>the memory region. What are the appropriate steps to do that? It seems
>as though that I cannot use the library stdio in pci device drivers. Is
>there another library that contains file IO?[/color]
Look in the kernel source for examples of sys_open, sys_read, etc.
--
[url]http://www.spinics.net/lists/[/url]
Re: PCI device driver question
I cannot find any good documentations on sys_open, sys_read, etc. What
are the parameters required to utilize those questions?
Let me rephrase what I wrote before. I have implemented a pci device
driver. I have the __init, __exit, probe, and remove functions just
like standard pci device drivers. Originally, in my probe function, I
tested the pci device driver by reading/writing to different base
address. On the FPGA, I had a simple test program involving LED's to
verify that I have read/write to the specific memory address.
Now, instead of writing/reading from the pci device driver, I want to
be able to do the reading/writing from the userspace. From the
userspace, I want to input a file using stdio that contains the data to
be written. I will then write out the data to the pci device driver.
My questions are:
a) In the pci device driver, do I need a write and read functions? Are
the functions similar to the char device driver read/write functions?
b) In the userspace, how do I access the pci device driver? The
previous poster mentioned to use sys_open, sys_read, sys_write, etc.
What are the parameters needed to utilize sys_open, sys_read,
sys_write, etc.? Do I need to know major/minor numbers?
[email]ellis@no.spam[/email] wrote:[color=blue]
> In article <1166736838.855581.113720@80g2000cwy.googlegroups.com>,
> [email]elliotng.ee@gmail.com[/email] <elliotng.ee@gmail.com> wrote:
>[color=green]
> >Now instead of hard-coding what to write in the memory region, I want
> >to input a file, read the file, and write the appropriate contents to
> >the memory region. What are the appropriate steps to do that? It seems
> >as though that I cannot use the library stdio in pci device drivers. Is
> >there another library that contains file IO?[/color]
>
> Look in the kernel source for examples of sys_open, sys_read, etc.
>
> --
> [url]http://www.spinics.net/lists/[/url][/color]
Re: PCI device driver question
OK, after doing some research, it appears that I can use the char
device read and write functions in the pci device driver. To summarize
what I have, I have written a pci device driver. In userspace, I want
to be able to access the pci device driver, read from memory, and write
to memory. I have recently found out that I can try to read/write from
using file operations.
Right now, this is what the file operations section of the pci device
driver looks like:
static int test_open(struct inode *inode, struct file *filp){
return 0;
}
static int test_release(struct inode *inode, struct file *filp){
return 0;
}
static ssize test_read(struct file *filp, char __user *buf, size_t
count, loff_t *f_pos){
// Code goes here
return 0;
}
static ssize test_write(struct file *filp, char __user *buf, size_t
count, loff_t *f_pos){
// Code goes here
return 0;
}
static struct file_operations test_fops = {
..open = test_open,
..read = test_read.
..write = test_write,
..release = test_release,
}
My questions are:
1) What do I put in for the read and write functions in the pci device
driver? I know that in write, I want to be able to use the function
void writel(unsigned value, char* address) in order to write to the
specified address. Similarly, for the read function, I want to be able
to use the function readl(char* address) to read the data from the
address.
2) In userspace code, how do I use fread and fwrite to a specific
memory location in the pci?
[email]elliotng.ee@gmail.com[/email] wrote:[color=blue]
> I cannot find any good documentations on sys_open, sys_read, etc. What
> are the parameters required to utilize those questions?
>
> Let me rephrase what I wrote before. I have implemented a pci device
> driver. I have the __init, __exit, probe, and remove functions just
> like standard pci device drivers. Originally, in my probe function, I
> tested the pci device driver by reading/writing to different base
> address. On the FPGA, I had a simple test program involving LED's to
> verify that I have read/write to the specific memory address.
>
> Now, instead of writing/reading from the pci device driver, I want to
> be able to do the reading/writing from the userspace. From the
> userspace, I want to input a file using stdio that contains the data to
> be written. I will then write out the data to the pci device driver.
>
> My questions are:
> a) In the pci device driver, do I need a write and read functions? Are
> the functions similar to the char device driver read/write functions?
> b) In the userspace, how do I access the pci device driver? The
> previous poster mentioned to use sys_open, sys_read, sys_write, etc.
> What are the parameters needed to utilize sys_open, sys_read,
> sys_write, etc.? Do I need to know major/minor numbers?
>
>
> [email]ellis@no.spam[/email] wrote:[color=green]
> > In article <1166736838.855581.113720@80g2000cwy.googlegroups.com>,
> > [email]elliotng.ee@gmail.com[/email] <elliotng.ee@gmail.com> wrote:
> >[color=darkred]
> > >Now instead of hard-coding what to write in the memory region, I want
> > >to input a file, read the file, and write the appropriate contents to
> > >the memory region. What are the appropriate steps to do that? It seems
> > >as though that I cannot use the library stdio in pci device drivers. Is
> > >there another library that contains file IO?[/color]
> >
> > Look in the kernel source for examples of sys_open, sys_read, etc.
> >
> > --
> > [url]http://www.spinics.net/lists/[/url][/color][/color]
Re: PCI device driver question
[email]elliotng.ee@gmail.com[/email] wrote:[color=blue]
> OK, after doing some research, it appears that I can use the char
> device read and write functions in the pci device driver. To summarize
> what I have, I have written a pci device driver. In userspace, I want
> to be able to access the pci device driver, read from memory, and write
> to memory. I have recently found out that I can try to read/write from
> using file operations.[/color]
(1) You need to map the device memory into kernel virtual address space
with ioremap. Then, in the test_write function, you copy data from
user space into kernel space (possibly to a small temporary holding
area), then use writel to put it into the (mapped) device memory
(adding in the f_pos value).
test_read is simply the inverse, readl to read the device memory space,
then copy it to user space.
copy_to_user and copy_from_user can be used for data transfer between
user space and kernel space. Look for the book "Linux Device Drivers"
(3rd edition) -- which is available in pdf format for free online --
for much detailed info.
(2) You create a device node (e.g. "mknod /dev/mydevice c xxx 0" where
xxx is your device's major number from /proc/devices). Your program
then opens /dev/mydevice, lseek's to the proper offset and does read or
write calls.
Having said all that, if this is just a one-off or occasional
special-purpose administrative operation, you may not even need to
write a driver (on most platforms at least). You can use the lspci
program to find the physical address of the pci device's memory. Then
you open "/dev/mem", mmap the desired area and read / write data
directly to or from it in your user program.
GH
Re: PCI device driver question
Thanks for your help. I followed this advice:
Having said all that, if this is just a one-off or occasional
special-purpose administrative operation, you may not even need to
write a driver (on most platforms at least). You can use the lspci
program to find the physical address of the pci device's memory. Then
you open "/dev/mem", mmap the desired area and read / write data
directly to or from it in your user program.
Following GH's advice, I looked at lspci, and found that the device
Region 0 memory is mapped at a0000000 (32-bit, prefetch, size=512 M)
I wrote the following program:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <asm/io.h>
int main(){
int memory;
unsigned int data;
unsigned char *address;
memory = open("/dev/mem", O_RDWR);
address = mmap((void*)0, 0xafffffff, PORT_WRITE | PORT_READ, MAP_FIXED,
memory, 0xa0000000);
data = readl(address);
printf("Data: %x", data);
writel(0xFF, address);
data = readl(address);
printf("Data: %x", data);
munmap((void*)address, 0xafffffff);
close(memory);
return 0;
}
I just want to make sure that my syntax is correct. When I went to run
the makefile, however, it did not work. It was having problems
recognizing readl and writel even though both functions should be in
<asm/io.h>. My makefile is the following:
testIO: testIO.c
gcc -o $@ $<
I have the following errors/warnings:
In file included from /usr/include/asm/io.h:11 from testIO.c:6:
/usr/include/asm-i386/io.h:1:2: warning: #warning "You should include
<sys/io.h>. This time I will do it for you."
testIO.c: (.text+0x59): undefined reference to 'readl'
testIO.c: (.text+0x82): undefined reference to 'writel'
testIO.c: (.text+0x90): undefined reference to 'readl'
[email]gil_hamilton@hotmail.com[/email] wrote:[color=blue]
> [email]elliotng.ee@gmail.com[/email] wrote:[color=green]
> > OK, after doing some research, it appears that I can use the char
> > device read and write functions in the pci device driver. To summarize
> > what I have, I have written a pci device driver. In userspace, I want
> > to be able to access the pci device driver, read from memory, and write
> > to memory. I have recently found out that I can try to read/write from
> > using file operations.[/color]
>
> (1) You need to map the device memory into kernel virtual address space
> with ioremap. Then, in the test_write function, you copy data from
> user space into kernel space (possibly to a small temporary holding
> area), then use writel to put it into the (mapped) device memory
> (adding in the f_pos value).
>
> test_read is simply the inverse, readl to read the device memory space,
> then copy it to user space.
>
> copy_to_user and copy_from_user can be used for data transfer between
> user space and kernel space. Look for the book "Linux Device Drivers"
> (3rd edition) -- which is available in pdf format for free online --
> for much detailed info.
>
> (2) You create a device node (e.g. "mknod /dev/mydevice c xxx 0" where
> xxx is your device's major number from /proc/devices). Your program
> then opens /dev/mydevice, lseek's to the proper offset and does read or
> write calls.
>
> Having said all that, if this is just a one-off or occasional
> special-purpose administrative operation, you may not even need to
> write a driver (on most platforms at least). You can use the lspci
> program to find the physical address of the pci device's memory. Then
> you open "/dev/mem", mmap the desired area and read / write data
> directly to or from it in your user program.
>
> GH[/color]
Re: PCI device driver question
Never mind, I found out that writel/readl are kernel functions. We will
need to emulate the kernel functions.
New code (just want to verify that it is correct):
......
// Kernel function emulation
#define writel(data, addr) *(volatile int*) (addr)=(data)
#define readl(addr) *(volatile int*)(addr)
int main(){
int memory;
unsigned int data;
unsigned char *address;
memory = open("/dev/mem", O_RDWR);
address = mmap((void*)0, 0x1fffffff, PORT_WRITE | PORT_READ, MAP_FIXED,
memory, 0x20000000);
data = readl(address);
printf("Data: %x", data);
writel(0xFF, address);
data = readl(address);
printf("Data: %x", data);
munmap((void*)address, 0x1fffffff);
close(memory);
return 0;
}