forked from Sepanta/pcie-driver
commit
8a9ed86fe1
5 changed files with 359 additions and 0 deletions
@ -0,0 +1,7 @@ |
|||
test |
|||
*.order |
|||
*.symvers |
|||
*.ko |
|||
*.mod |
|||
*.mod.* |
|||
*.o |
@ -0,0 +1,21 @@ |
|||
# If KERNELRELEASE is defined, we've been invoked from the
|
|||
# kernel build system and can use its language.
|
|||
# Otherwise we were called directly from the command
|
|||
# line; invoke the kernel build system.
|
|||
|
|||
ifneq ($(KERNELRELEASE),) |
|||
obj-m := usdpci.o |
|||
else |
|||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build |
|||
PWD := $(shell pwd) |
|||
|
|||
default: |
|||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules |
|||
clean: |
|||
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean |
|||
endif |
|||
|
|||
install: |
|||
sudo cp ./usdpci.ko /lib/modules/`uname -r`/ |
|||
sudo depmod -a |
|||
sudo cp usdpci.rules /etc/udev/rules.d/ |
@ -0,0 +1,7 @@ |
|||
sudo rmmod usdpci |
|||
make clean |
|||
make |
|||
sudo make install |
|||
sudo insmod usdpci.ko |
|||
dmesg |
|||
echo hello |
@ -0,0 +1,322 @@ |
|||
#include <linux/init.h> |
|||
|
|||
#include <linux/module.h> |
|||
|
|||
#include <linux/pci.h> |
|||
#include <linux/pci_ids.h> |
|||
#include <linux/interrupt.h> |
|||
|
|||
#include <linux/highmem.h> |
|||
|
|||
#include <linux/spinlock.h> |
|||
#include <linux/spinlock_types.h> |
|||
|
|||
#include <linux/fs.h> |
|||
#include <linux/cdev.h> |
|||
|
|||
#include <linux/sched.h> |
|||
#include <linux/wait.h> |
|||
#include <linux/delay.h> |
|||
#include <linux/poll.h> |
|||
|
|||
|
|||
#define DMA_ADDR_OFFSET 32 |
|||
#define PRINT(A) printk(KERN_ALERT ">>>>> #A %x\n", A); |
|||
|
|||
MODULE_AUTHOR("Talaie"); |
|||
MODULE_LICENSE("Dual BSD/GPL"); |
|||
|
|||
static struct pci_device_id pcie_ids[] = |
|||
{ |
|||
{PCI_DEVICE(0x10ee, 0x7024)}, |
|||
{0, }, |
|||
}; |
|||
MODULE_DEVICE_TABLE(pci, pcie_ids); |
|||
|
|||
static irqreturn_t interrupt_handler(int irq, void *p); |
|||
|
|||
static struct pci_dev *pcidev = NULL; |
|||
|
|||
static unsigned int chrdev_major = 0; |
|||
static unsigned int chrdev_minor = 0; |
|||
|
|||
static unsigned int ioctl_alloc_dma = 0; |
|||
static unsigned int ioctl_refresh_link = 1; |
|||
|
|||
static unsigned long bar0_addr; |
|||
static unsigned long bar0_size = 4*1024; //TODO ask about size. 4KB
|
|||
static void* bar0_ptr; |
|||
static unsigned int irq; |
|||
|
|||
|
|||
struct page** dma_pages = NULL; |
|||
unsigned int dma_pages_count = 0; |
|||
void* dma_addr = NULL; |
|||
unsigned long mmap_buffersize = 4 * 1024; //4KB
|
|||
|
|||
|
|||
|
|||
/*************************************************************************************************/ |
|||
static int __init pcie_init(void); |
|||
static int chrdev_init(void); |
|||
static int usd_open(struct inode *inode, struct file *flip); |
|||
static int usd_mmap(struct file *filp, struct vm_area_struct *vma); |
|||
static unsigned int usd_poll (struct file *filp, poll_table *wait); |
|||
static int __init pcie_probe (struct pci_dev *dev, const struct pci_device_id *id); |
|||
static void pcie_remove(struct pci_dev *dev); |
|||
static void __exit pcie_exit(void); |
|||
|
|||
/*************************************************************************************************/ |
|||
static dev_t chrdev; |
|||
static struct cdev cdev; |
|||
static struct class *class = NULL; |
|||
|
|||
#define DEV_NAME "usd_reg" |
|||
|
|||
struct file_operations chrdev_fops = |
|||
{ |
|||
.owner = THIS_MODULE, |
|||
.open = usd_open, |
|||
.mmap = usd_mmap, |
|||
.poll = usd_poll |
|||
}; |
|||
|
|||
/*************************************************************************************************/ |
|||
static struct pci_driver pci_driver = |
|||
{ |
|||
.name = "usdpci", |
|||
.id_table = pcie_ids, |
|||
.probe = pcie_probe, |
|||
.remove = __exit_p(pcie_remove), |
|||
}; |
|||
|
|||
/*************************************************************************************************/ |
|||
#define PRINT_PREFIX "USDriver PCIe" |
|||
#define PRINT_ALERT(STR) printk(KERN_ALERT "%s %s\n", PRINT_PREFIX, STR) |
|||
#define PRINT_WARN(STR) printk(KERN_WARN "%s %s\n", PRINT_PREFIX, STR) |
|||
|
|||
/*************************************************************************************************/ |
|||
static int __init pcie_init(void) |
|||
{ |
|||
int res = 0; |
|||
PRINT_ALERT("driver initializing"); |
|||
|
|||
res = pci_register_driver(&pci_driver); |
|||
if ( res ) { |
|||
PRINT_ALERT("device not found"); |
|||
return res; |
|||
} |
|||
|
|||
PRINT_ALERT("register driver success" ); |
|||
|
|||
res = chrdev_init(); |
|||
if ( res ) { |
|||
PRINT_ALERT("character device file creation failed"); |
|||
return res; |
|||
} |
|||
|
|||
PRINT_ALERT("driver loaded"); |
|||
return res; |
|||
} |
|||
|
|||
/*************************************************************************************************/ |
|||
static int chrdev_init(void) |
|||
{ |
|||
PRINT_ALERT("chrdev_init"); |
|||
|
|||
int res = 0; |
|||
struct device *device = NULL; |
|||
|
|||
res = alloc_chrdev_region(&chrdev, 0, 1, DEV_NAME); |
|||
|
|||
if(res < 0) |
|||
{ |
|||
return -1; |
|||
} |
|||
|
|||
cdev_init(&cdev, &chrdev_fops); |
|||
res = cdev_add(&cdev, chrdev, 1); |
|||
|
|||
if (res) |
|||
{ |
|||
unregister_chrdev_region(chrdev, 1); |
|||
return res; |
|||
} |
|||
|
|||
class = class_create(THIS_MODULE, "usdpci"); |
|||
device = device_create(class, NULL, 0, NULL, "usd_regs0"); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
/*************************************************************************************************/ |
|||
static int usd_open(struct inode *inode, struct file *flip) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
/*************************************************************************************************/ |
|||
static int usd_mmap(struct file *filp, struct vm_area_struct *vma) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
/*************************************************************************************************/ |
|||
static unsigned int usd_poll (struct file *filp, poll_table *wait) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
/*************************************************************************************************/ |
|||
static int __init pcie_probe (struct pci_dev *dev, const struct pci_device_id *id) |
|||
{ |
|||
bar0_ptr = pci_iomap(dev, 0, 64 * 1024);//4KB
|
|||
u8* bar0_data = (u8*)bar0_ptr; |
|||
int rc = 0; |
|||
|
|||
if(bar0_data == 0) |
|||
{ |
|||
PRINT_ALERT("driver failed to map BAR 0"); |
|||
rc = 1; |
|||
goto probe_fail_release_region; |
|||
} |
|||
|
|||
pci_set_master(dev); |
|||
|
|||
// int i = 0;
|
|||
// for( i = 0; i < 1; i++)
|
|||
// {
|
|||
// int r32 = ioread32(&bar0_data[i*4]);
|
|||
// printk(KERN_ALERT "Read: %x (%d)\n", r32, i);
|
|||
// }
|
|||
|
|||
iowrite32(0x45670000, &bar0_data[0x8018]); |
|||
int r32 = ioread32(&bar0_data[0x8018]); |
|||
printk(KERN_ALERT "Read: %x\n", r32); |
|||
return 0; |
|||
|
|||
probe_fail_release_region: |
|||
pci_release_regions(dev); |
|||
probe_fail: |
|||
pci_disable_device(dev); |
|||
probe_fail_enable: |
|||
return rc; |
|||
} |
|||
|
|||
/*************************************************************************************************/ |
|||
static void pcie_remove(struct pci_dev *dev) |
|||
{ |
|||
PRINT_ALERT("remove driver"); |
|||
|
|||
int i; |
|||
u8* bar0_data; |
|||
bar0_data = (u8*)bar0_ptr; |
|||
for ( i = 0; i < dma_pages_count; i++ ) { |
|||
pci_unmap_single(pcidev, bar0_data[DMA_ADDR_OFFSET + 4*i], PAGE_SIZE, DMA_BIDIRECTIONAL); |
|||
__free_page(dma_pages[i]); |
|||
} |
|||
if (dma_pages != NULL) kfree(dma_pages); |
|||
printk(KERN_ALERT "Freed DMA pages\n"); |
|||
|
|||
pci_clear_master(dev); |
|||
printk(KERN_ALERT "Cleared PCIe master\n"); |
|||
|
|||
pci_iounmap(dev, bar0_ptr); |
|||
printk(KERN_ALERT "IOunmap\n"); |
|||
|
|||
pci_release_regions(dev); |
|||
printk(KERN_ALERT "pci_release_regions\n"); |
|||
|
|||
pci_disable_device(dev); |
|||
printk(KERN_ALERT "pci_disable_device\n"); |
|||
} |
|||
|
|||
/*************************************************************************************************/ |
|||
static void __exit pcie_exit(void) |
|||
{ |
|||
int i; |
|||
u8* bar0_data; |
|||
bar0_data = (u8*)bar0_ptr; |
|||
|
|||
printk(KERN_ALERT "USDriver PCIe driver unloading\n"); |
|||
|
|||
printk(KERN_ALERT "USDriver PCIe driver unregistering\n"); |
|||
pci_unregister_driver(&pci_driver); |
|||
|
|||
printk(KERN_ALERT "USDriver PCIe unregister_chrdev_region\n"); |
|||
unregister_chrdev_region(chrdev, 1); |
|||
|
|||
printk(KERN_ALERT "USDriver PCIe cdev_del\n"); |
|||
cdev_del(&cdev); |
|||
|
|||
printk(KERN_ALERT "USDriver PCIe device_destroy\n"); |
|||
device_destroy(class, chrdev); |
|||
|
|||
printk(KERN_ALERT "USDriver PCIe class_destroy\n"); |
|||
class_destroy(class); |
|||
printk(KERN_ALERT "USDriver PCIe driver unloaded\n"); |
|||
} |
|||
|
|||
module_init(pcie_init); |
|||
module_exit(pcie_exit); |
|||
|
|||
/*************************************************************************************************/ |
|||
|
|||
static int create_dma_buffer(unsigned int bufcount) |
|||
{ |
|||
int i; |
|||
int bufidx = 0; |
|||
unsigned int gfp_mask = GFP_KERNEL | __GFP_DMA; |
|||
dma_addr_t bus_addr; |
|||
u8* bar0_data; |
|||
bar0_data = (u8*)bar0_ptr; |
|||
|
|||
printk(KERN_ALERT "USDriver DMA buffer alloc request: %d pages\n", bufcount); |
|||
if( dma_pages != NULL) |
|||
{ |
|||
printk(KERN_ALERT "USDriver DMA buffer already exist! Strange!\n"); |
|||
} |
|||
|
|||
dma_pages = kmalloc(4*1024*1024 * bufcount, GFP_KERNEL); |
|||
if(dma_pages == NULL) |
|||
{ |
|||
printk(KERN_ERR "USDriver DMA dma_pages alloc failed! \n" ); |
|||
return 1; |
|||
} |
|||
|
|||
for(bufidx = 0; bufidx < bufcount; bufidx++) |
|||
{ |
|||
void __iomem *maddr = NULL; |
|||
struct page *pages = alloc_pages(gfp_mask, 10); |
|||
if(pages == NULL) |
|||
{ |
|||
printk(KERN_ERR "USDriver DMA buffer alloc failed! \n" ); |
|||
return 1; |
|||
} |
|||
maddr = page_address(pages); |
|||
dma_pages[bufidx] = pages; |
|||
|
|||
bus_addr = pci_map_single(pcidev, maddr, 1024 * PAGE_SIZE, DMA_BIDIRECTIONAL); |
|||
printk(KERN_ALERT ">>>>>[%d] 0x%x\n", bufidx, bus_addr); |
|||
iowrite32(bus_addr, &bar0_data[DMA_ADDR_OFFSET + (4 * bufidx)]); |
|||
wmb(); |
|||
if(pci_dma_mapping_error(pcidev, bus_addr)) |
|||
{ |
|||
return 1; |
|||
} |
|||
} |
|||
dma_pages_count = bufcount; |
|||
|
|||
printk(KERN_ALERT "USDriver DMA buffer alloc successful\n"); |
|||
return 0; |
|||
} |
|||
|
|||
|
|||
/*************************************************************************************************/ |
|||
/*************************************************************************************************/ |
|||
/*************************************************************************************************/ |
|||
/*************************************************************************************************/ |
|||
/*************************************************************************************************/ |
|||
/*************************************************************************************************/ |
|||
/*************************************************************************************************/ |
|||
/*************************************************************************************************/ |
@ -0,0 +1,2 @@ |
|||
ACTION=="add",SUBSYSTEM=="pci",ATTR{vendor}=="0x10ee", ATTR{device}="0x0007", RUN+="/sbin/modprobe uscpci" |
|||
KERNEL=="usd_regs0",MODE="666" |
Loading…
Reference in new issue