Oh no! I need to write a PCI driver!

Photo by Markus Spiske on Unsplash

Start with a working example

Step by step debug guide

Photo by Jason Leung on Unsplash
user@mypc:~$ lspci
0001:00:00.0 PCI bridge: NVIDIA Corporation Device 1ad2 (rev a1)
0001:01:00.0 SATA controller: Marvell Technology Group Ltd. Device 9171 (rev 13)
user@mypc:~$ lspci -vmm
Slot: 0001:00:00.0
Class: PCI bridge
Vendor: NVIDIA Corporation
Device: Device 1ad2
Rev: a1
Slot: 0001:01:00.0
Class: SATA controller
Vendor: Marvell Technology Group Ltd.
Device: Device 9171
SVendor: Marvell Technology Group Ltd.
SDevice: Device 9171
Rev: 13
ProgIf: 01
Set Device and Vendor IDs in Xilinx’s XDMA IP
user@mypc:~$ lspci -vmn
Device: 0001:00:00.0
Class: 0604
Vendor: 10de
Device: 1ad2
Rev: a1
Device: 0001:01:00.0
Class: 0106
Vendor: 1b4b
Device: 9171
SVendor: 1b4b
SDevice: 9171
Rev: 13
ProgIf: 01
user@mypc:~$ insmod mydriver.ko
user@mypc:~$ lsmod
Module Size Used by
mydriver 28503 0
fuse 103841 3
nvgpu 1579891 21 picoevb_rdma
ip_tables 19441 0
x_tables 28951 1 ip_tables
Photo by Kevin Jarrett on Unsplash

Probing function gets called (during execution of pci_register_driver() for already existing devices or later if a new device gets inserted) for all PCI devices which match the ID table and are not “owned” by the other drivers yet. This function gets passed a “struct pci_dev *” for each device whose entry in the ID table matches the device. The probe function returns zero when the driver chooses to take “ownership” of the device or an error code (negative number) otherwise. The probe function always gets called from process context, so it can sleep.

user@mypc:~$ lspci -v
0005:01:00.0 Memory controller: NVIDIA Corporation Device 8034
Subsystem: NVIDIA Corporation Device 0001
Flags: bus master, fast devsel, latency 0, IRQ 39
Memory at 1f40000000 (32-bit, non-prefetchable) [size=512M]
... Capabilities: [300] #19
Kernel driver in use: mydriver
user@mypc:~$ ls /dev/mydriver
/dev/mydriver
static ssize_t fops_read(struct file *filep, char *buffer, size_t len, loff_t *offset_ptr){
int error_count = 0;
char kbuff[2048]; // kernel buffer
int kbuff_len = 2048;
loff_t offset = *offset_ptr;
printk(KERN_CRIT "Open start");

if(offset > 0){
// End of file Does not support to read more chuks, seek etc...
return 0;
}
offset += snprintf(kbuff, kbuff_len, "Hello from My driver\n");error_count = copy_to_user(buffer, kbuff, offset);if (error_count==0){ // if true then have success
printk(KERN_CRIT "Read success!\n");
*offset_ptr = offset; // Increment the offset
return offset; // Return the count of the read character
}
else {
printk(KERN_CRIT "Failed to send %d characters\n", error_count);
return -EFAULT;
}
}
user@mypc:~$ cat /dev/mydriver
Hello from My driver
user@mypc:~$
user@mypc:~$ lspci -v
0005:01:00.0 Memory controller: NVIDIA Corporation Device 8034
Subsystem: NVIDIA Corporation Device 0001
Flags: bus master, fast devsel, latency 0, IRQ 39
Memory at 1f40000000 (32-bit, non-prefetchable) [size=512M]
Memory at 1f60000000 (32-bit, non-prefetchable) [size=64K]

Capabilities: [80] Power Management version 3
...
busybox devmem <BAR + device_register> # Read a register
busybox devmem <BAR + device_register> w <value> # Write a register
Photo by Jonathan Chng on Unsplash

Sum

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store