#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*************************************************************************************************/ #define PRINT(A) printk(KERN_ALERT ">>>>> #A %x\n", A); /*************************************************************************************************/ MODULE_AUTHOR("h4ndh"); //hediyehloo based on Talaee works MODULE_LICENSE("Dual BSD/GPL"); /*************************************************************************************************/ static struct pci_device_id pcie_ids[] = { {PCI_DEVICE(0x10ee, 0x7024)}, {0, }, }; MODULE_DEVICE_TABLE(pci, pcie_ids); /*************************************************************************************************/ static struct pci_dev *pcidev = NULL; /*************************************************************************************************/ static int pcie_init(void); static void pcie_exit(void); static int pcie_probe (struct pci_dev *dev, const struct pci_device_id *id); static void pcie_remove(struct pci_dev *dev); static int chrdev_init(void); static int usd_open_0(struct inode *inode, struct file *flip); static int usd_close_0(struct inode *inode, struct file *filp); static int usd_mmap_0(struct file *filp, struct vm_area_struct *vma); static int usd_open_1(struct inode *inode, struct file *flip); static int usd_close_1(struct inode *inode, struct file *filp); static int usd_mmap_1(struct file *filp, struct vm_area_struct *vma); static int usd_open_2(struct inode *inode, struct file *flip); static int usd_close_2(struct inode *inode, struct file *filp); static int usd_mmap_2(struct file *filp, struct vm_area_struct *vma); /*************************************************************************************************/ static dev_t chrdev; static struct cdev cdev; static struct class *class = NULL; #define DEV_NAME "usd_reg" #define CLASS_NAME "usdpci" /*************************************************************************************************/ #define TOTAL_BAR_NUM 2 struct bar_t{ unsigned long bar_addr; unsigned long bar_size; void* bar_ptr; struct file_operations chrdev_fops; }; struct bar_t bars[TOTAL_BAR_NUM]; /*************************************************************************************************/ static struct pci_driver pci_driver = { .name = CLASS_NAME, .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; } //gone have 3 bar for now bars[0].chrdev_fops.owner = THIS_MODULE; bars[0].chrdev_fops.open = usd_open_0; bars[0].chrdev_fops.mmap = usd_mmap_0; bars[0].chrdev_fops.release = usd_close_0; bars[0].bar_size = 4 * 1024; bars[1].chrdev_fops.owner = THIS_MODULE; bars[1].chrdev_fops.open = usd_open_1; bars[1].chrdev_fops.mmap = usd_mmap_1; bars[1].chrdev_fops.release = usd_close_1; bars[1].bar_size = 128 * 1024 * 1024; // bars[2].chrdev_fops = { // .owner = THIS_MODULE, // .open = usd_open_2, // .mmap = usd_mmap_2, // .release = usd_close_2 // }; // bars[2].bar_size = 4 * 1024; 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"); char name[16]; int i = 0; for( ;i < TOTAL_BAR_NUM; i++) { sprintf(name, "%s_%d", DEV_NAME, i); proc_create(name, 0, NULL, &bars[i].chrdev_fops); } return 0; } /*************************************************************************************************/ static int usd_open_0(struct inode *inode, struct file *filp) { return 0; } /*************************************************************************************************/ static int usd_open_1(struct inode *inode, struct file *filp) { return 0; } /*************************************************************************************************/ static int usd_open_2(struct inode *inode, struct file *filp) { return 0; } /*************************************************************************************************/ static int usd_close_0(struct inode *inode, struct file *filp) { return 0; } /*************************************************************************************************/ static int usd_close_1(struct inode *inode, struct file *filp) { return 0; } /*************************************************************************************************/ static int usd_close_2(struct inode *inode, struct file *filp) { return 0; } /*************************************************************************************************/ static int usd_mmap_0(struct file *filp, struct vm_area_struct *vma) { PRINT_ALERT("MMAP"); unsigned long off = vma->vm_pgoff << PAGE_SHIFT; unsigned long vsize = vma->vm_end - vma->vm_start; unsigned long physical = bars[0].bar_addr + off; unsigned int intvsize = bars[0].bar_size - off; // these are required for io maps, but is it okay for the buffer as well? vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_flags |= VM_IO; if ( vsize < intvsize ) intvsize = vsize; remap_pfn_range(vma, vma->vm_start, physical>>PAGE_SHIFT, intvsize, vma->vm_page_prot); return 0; } /*************************************************************************************************/ static int usd_mmap_1(struct file *filp, struct vm_area_struct *vma) { PRINT_ALERT("MMAP"); unsigned long off = vma->vm_pgoff << PAGE_SHIFT; unsigned long vsize = vma->vm_end - vma->vm_start; unsigned long physical = bars[1].bar_addr + off; unsigned int intvsize = bars[1].bar_size - off; // these are required for io maps, but is it okay for the buffer as well? vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_flags |= VM_IO; if ( vsize < intvsize ) intvsize = vsize; remap_pfn_range(vma, vma->vm_start, physical>>PAGE_SHIFT, intvsize, vma->vm_page_prot); return 0; } /*************************************************************************************************/ static int usd_mmap_2(struct file *filp, struct vm_area_struct *vma) { PRINT_ALERT("MMAP"); unsigned long off = vma->vm_pgoff << PAGE_SHIFT; unsigned long vsize = vma->vm_end - vma->vm_start; unsigned long physical = bars[2].bar_addr + off; unsigned int intvsize = bars[2].bar_size - off; // these are required for io maps, but is it okay for the buffer as well? vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_flags |= VM_IO; if ( vsize < intvsize ) intvsize = vsize; remap_pfn_range(vma, vma->vm_start, physical>>PAGE_SHIFT, intvsize, vma->vm_page_prot); return 0; } /*************************************************************************************************/ static int __init pcie_probe (struct pci_dev *dev, const struct pci_device_id *id) { int rc = 0; rc = pci_enable_device(dev); if(rc) { PRINT_ALERT("driver pci_enable_device() failed"); goto probe_fail_enable; } /***************BAR 0***********************/ if(!(pci_resource_flags(dev, 0) & IORESOURCE_MEM)) { printk(KERN_ERR "USDriver PCIe driver incorrect BAR configuration\n" ); rc = 1; goto probe_fail; } bars[0].bar_addr = pci_resource_start(dev, 0); rc = pci_request_region(dev, 0, "bar0"); if(rc) { PRINT_ALERT("driver pci_request_regions bar0 failed"); goto probe_fail; } bars[0].bar_ptr = pci_iomap(dev, 0, bars[0].bar_size); u32* bar0_data = (u32*)bars[0].bar_ptr; if(bar0_data == 0) { PRINT_ALERT("driver failed to map BAR 0"); rc = 1; goto probe_fail_release_region; } if(!(pci_resource_flags(dev, 1) & IORESOURCE_MEM)) { printk(KERN_ERR "USDriver PCIe driver incorrect BAR configuration\n" ); rc = 1; goto probe_fail; } bars[1].bar_addr = pci_resource_start(dev, 1); rc = pci_request_region(dev, 1, "bar1"); if(rc) { PRINT_ALERT("driver pci_request_regions bar1 failed"); goto probe_fail; } bars[1].bar_ptr = pci_iomap(dev, 1, bars[1].bar_size); u32* bar1_data = (u32*)bars[1].bar_ptr; if(bar1_data == 0) { PRINT_ALERT("driver failed to map BAR 1"); rc = 1; goto probe_fail_release_region; } pci_set_master(dev); printk(KERN_ALERT "-----------------------------------\n"); printk(KERN_ALERT "BAR0 reg 0 = 0x%x\n", *bar0_data); *bar1_data = 0x12345678; printk(KERN_ALERT "BAR1 reg 0 = 0x%x\n", ioread32(bar1_data)); printk(KERN_ALERT "-----------------------------------\n"); 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"); pci_clear_master(dev); PRINT_ALERT("Cleared PCIe master"); pci_iounmap(dev, bars[0].bar_ptr); pci_iounmap(dev, bars[1].bar_ptr); PRINT_ALERT("IOunmap"); pci_release_regions(dev); PRINT_ALERT("pci_release_regions"); pci_disable_device(dev); PRINT_ALERT("pci_disable_device"); } /*************************************************************************************************/ static void __exit pcie_exit(void) { PRINT_ALERT("driver unloading"); PRINT_ALERT("driver unregistering"); pci_unregister_driver(&pci_driver); char name[16]; int i = 0; for( ; i < TOTAL_BAR_NUM; i++) { snprintf(name, 8, "%s%d", DEV_NAME, i); remove_proc_entry(name, NULL); } PRINT_ALERT("driver unloaded"); } module_init(pcie_init); module_exit(pcie_exit); /*************************************************************************************************/ /*************************************************************************************************/ /*************************************************************************************************/ /*************************************************************************************************/ /*************************************************************************************************/ /*************************************************************************************************/ /*************************************************************************************************/ /*************************************************************************************************/