Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/next/external/cache/sources/linuxpg/pgdrv.c
Views: 3959
#include <linux/version.h>1#include <linux/module.h>2#include <linux/cdev.h>3#include <linux/kernel.h>4#include <linux/delay.h>5#include <linux/interrupt.h>6#include <linux/pci.h>7#include <linux/fs.h> // struct file_operations8#include <linux/mm.h> // mmap9#include <linux/slab.h> // kmalloc10#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)11#include <linux/pci-aspm.h>12#endif13#include <asm/io.h>14#include <asm/uaccess.h> // copy_to_user15#include <linux/uaccess.h> // copy_to_user16#include <asm/byteorder.h>1718#include "pgdrv.h"1920#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)21#warning KERNEL_VERSION < 2.6.1122#endif2324static DEV_INFO dev_info[MAX_DEV_NUM];25static atomic_t dev_num;26static spinlock_t module_lock;27static int major = 0;28static unsigned long mmio = 0;2930module_param(major, int, S_IRUGO|S_IWUSR);31module_param(mmio, ulong, S_IRUGO|S_IWUSR);3233//static int dev_IoctlFun(struct inode *inode, struct file *pFile,unsigned int cmd, unsigned long arg)34static long dev_IoctlFun(struct file *pFile,unsigned int cmd, unsigned long arg)35{36PPGDEV mydev;37int result;3839if (_IOC_TYPE(cmd) != RTL_IOC_MAGIC)40{41DbgFunPrint("Invalid command!!!");42return -ENOTTY;43}4445mydev = (PPGDEV)pFile->private_data;46result = 0;4748#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)49if (down_interruptible(&mydev->dev_sem))50{51DbgFunPrint("lock fail");52return -ERESTARTSYS;53}54#else55if (mutex_lock_interruptible(&mydev->dev_mutex))56{57DbgFunPrint("lock fail");58return -ERESTARTSYS;59}60#endif6162switch(cmd)63{64case IOC_PCI_CONFIG:65{66PCI_CONFIG_RW pci_config;6768if (copy_from_user(&pci_config, (void __user *)arg, sizeof(PCI_CONFIG_RW)))69{70DbgFunPrint("copy_from_user fail");71result = -EFAULT;72break;73}747576if (pci_config.bRead==TRUE)77{78if (pci_config.size==1)79{80result = pci_read_config_byte(mydev->pdev, pci_config.addr, &pci_config.byte);81}82else if (pci_config.size==2)83{84result = pci_read_config_word(mydev->pdev, pci_config.addr, &pci_config.word);85}86else if (pci_config.size==4)87{88result = pci_read_config_dword(mydev->pdev, pci_config.addr, &pci_config.dword);89}90else91{92result = -EINVAL;93}9495if (result)96{97DbgFunPrint("Read PCI fail:%d",result);98break;99}100101if (copy_to_user((void __user *)arg , &pci_config, sizeof(PCI_CONFIG_RW)))102{103DbgFunPrint("copy_from_user fail");104result = -EFAULT;105break;106}107}108else // write109{110if (pci_config.size==1)111{112result = pci_write_config_byte(mydev->pdev, pci_config.addr, pci_config.byte);113}114else if (pci_config.size==2)115{116result = pci_write_config_word(mydev->pdev, pci_config.addr, pci_config.word);117}118else if (pci_config.size==4)119{120result = pci_write_config_dword(mydev->pdev, pci_config.addr, pci_config.dword);121}122else123{124result = -EINVAL;125}126127if (result)128{129DbgFunPrint("Write PCI fail:%d",result);130break;131}132}133#if 0134DebugPrint("bRead=%u, size=%d, addr=0x%02x , data=0x%08x",135pci_config.bRead, pci_config.size,136pci_config.addr, pci_config.dword);137#endif138break;139}140141case IOC_IOMEM_OFFSET:142if ( put_user(mydev->offset,(unsigned int __user *)arg) )143{144DbgFunPrint("put_user fail");145result = -EFAULT;146break;147}148break;149150case IOC_DEV_FUN:151if ( put_user(mydev->pdev->devfn,(unsigned int __user *)arg) )152{153DbgFunPrint("put_user fail");154result = -EFAULT;155break;156}157break;158159default:160DbgFunPrint("Command not support!!!");161result = -ENOTTY;162break;163}164165#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)166up(&mydev->dev_sem);167#else168mutex_unlock(&mydev->dev_mutex);169#endif170return result;171}172173ssize_t dev_read(struct file *filp, char __user *buffer, size_t count, loff_t *f_pos)174{175PPGDEV mydev;176BYTE *buf;177ssize_t readcount;178179DbgFunPrint("count=%zd",count);180mydev = (PPGDEV)filp->private_data;181#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)182if (down_interruptible(&mydev->dev_sem))183{184DbgFunPrint("lock fail");185return 0;186}187#else188if (mutex_lock_interruptible(&mydev->dev_mutex))189{190DbgFunPrint("lock fail");191return 0;192}193#endif194195// To Do:196if (count > 0x100)197{198count = 0x100;199// return 0;200}201else202{203count &= ~0x3;204}205buf = kmalloc(count,GFP_KERNEL);206if (!buf)207{208return -ENOMEM;209}210211for (readcount=0;readcount<count;readcount+=4)212{213if (pci_read_config_dword(mydev->pdev,readcount,(u32 *)&buf[readcount]))214{215break;216}217}218219if (copy_to_user(buffer,buf,readcount))220{221readcount = 0;222}223*f_pos += readcount;224225kfree(buf);226#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)227up(&mydev->dev_sem);228#else229mutex_unlock(&mydev->dev_mutex);230#endif231return readcount;232}233234static int dev_Open(struct inode *inode, struct file *pFile)235{236PPGDEV mydev;237238mydev = container_of(inode->i_cdev, PGDEV, cdev);239DbgFunPrint("mydev=%p",mydev);240241#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)242atomic_inc(&mydev->count);243if (atomic_read(&mydev->count) > 1)244{245atomic_dec(&mydev->count);246DbgFunPrint("Busy");247return -EMFILE;248}249#else250if (atomic_inc_return(&mydev->count) > 1)251{252atomic_dec(&mydev->count);253DbgFunPrint("Busy");254return -EMFILE;255}256#endif257258pFile->private_data = mydev;259260return 0;261}262263static int dev_Close(struct inode *inode, struct file *pFile)264{265PPGDEV mydev;266267mydev = container_of(inode->i_cdev, PGDEV, cdev);268DbgFunPrint("mydev=%p",mydev);269pFile->private_data = NULL;270271atomic_dec(&mydev->count);272273return 0;274}275276static void dev_vma_open(struct vm_area_struct *vma)277{278DebugPrint("dev_vma_open");279// DbgFunPrint("vma=0x%08x, vm_start=0x%08x, vm_end=0x%08x, vm_pgoff=%d\n",280// (DWORD)vma, (DWORD)vma->vm_start, (DWORD)vma->vm_end,281// (DWORD)vma->vm_pgoff);282}283284static void dev_vma_close(struct vm_area_struct *vma)285{286DebugPrint("dev_vma_close");287// DbgFunPrint("vma=0x%08x, vm_start=0x%08x, vm_end=0x%08x, vm_pgoff=%d\n",288// (DWORD)vma, (DWORD)vma->vm_start, (DWORD)vma->vm_end,289// (DWORD)vma->vm_pgoff);290}291292static struct vm_operations_struct dev_vma_ops = {293.open = dev_vma_open,294.close = dev_vma_close,295};296297static int dev_mmap(struct file *filp, struct vm_area_struct *vma)298{299PPGDEV mydev;300301mydev = (PPGDEV)filp->private_data;302303if (!mydev)304{305DbgFunPrint("NULL pointer");306return -EFAULT;307}308DbgFunPrint("\nvma=%p, vm_start=0x%08x, vm_end=0x%08x\nvm_pgoff=%d, vm_flags=0x%x, mydev=%p\n",309vma, (DWORD)vma->vm_start, (DWORD)vma->vm_end,310(DWORD)vma->vm_pgoff,(DWORD)vma->vm_flags,311mydev);312313if (!mydev || !mydev->base_phyaddr)314{315DbgFunPrint("Invalid base_phyaddr=0x%08x",(DWORD)mydev->base_phyaddr);316return -ENXIO;317}318319switch(mydev->deviceID)320{321case 0x8167:322case 0x8169:323{324unsigned int iomem;325pci_read_config_dword(mydev->pdev, 0x14, &iomem);326if (!iomem)327{328DbgFunPrint("Invalid iomem=0x%08x, base_phyaddr=0x%08x",iomem,(DWORD)mydev->base_phyaddr);329pci_write_config_dword(mydev->pdev, 0x14, (DWORD)mydev->base_phyaddr);330}331break;332}333334default:335break;336}337338vma->vm_flags |= VM_IO;339#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)340if (remap_page_range(vma, vma->vm_start, mydev->base_phyaddr, vma->vm_end-vma->vm_start, vma->vm_page_prot))341{342DbgFunPrint("remap_page_range fail!!!");343return -EAGAIN;344}345#else346vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);347if (remap_pfn_range(vma, vma->vm_start, mydev->base_phyaddr>>PAGE_SHIFT, vma->vm_end-vma->vm_start, vma->vm_page_prot))348{349DbgFunPrint("remap_pfn_range fail!!!");350return -EAGAIN;351}352#endif353vma->vm_ops = &dev_vma_ops;354dev_vma_open(vma);355return 0;356}357358static struct file_operations pg_fops = {359.owner = THIS_MODULE,360.read = dev_read,361// .write = NsmWriteFun,362.mmap = dev_mmap,363.unlocked_ioctl = dev_IoctlFun,364.open = dev_Open,365.release = dev_Close,366};367368static int __devinit pgdrv_prob(struct pci_dev *pdev, const struct pci_device_id *id)369{370PPGDEV mydev;371dev_t devno;372int pg_minor, result, i;373374#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)375pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |376PCIE_LINK_STATE_CLKPM);377#endif378379#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)380atomic_inc(&dev_num);381if (atomic_read(&dev_num) > MAX_DEV_NUM)382{383atomic_dec(&dev_num);384DbgFunPrint("Too Many Device");385return -EFAULT;386}387#else388if (atomic_inc_return(&dev_num) > MAX_DEV_NUM)389{390atomic_dec(&dev_num);391DbgFunPrint("Too Many Device");392return -EFAULT;393}394#endif395396mydev = kmalloc(sizeof(PGDEV),GFP_KERNEL);397if (!mydev)398{399DebugPrint("Allocate dev fail");400return -ENOMEM;401}402memset(mydev, 0, sizeof(PGDEV));403404pg_minor = -1;405devno = 0;406spin_lock(&module_lock);407for (i = 0; i < MAX_DEV_NUM; i++)408{409if (dev_info[i].bUsed == FALSE)410{411dev_info[i].bUsed = TRUE;412devno = dev_info[i].devno;413mydev->index = i;414break;415}416}417spin_unlock(&module_lock);418419mydev->pdev = pdev;420atomic_set(&mydev->count, 0);421#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)422init_MUTEX(&mydev->dev_sem);423#else424mutex_init(&mydev->dev_mutex);425#endif426427pg_minor = MINOR(devno);428DbgFunPrint("mydev=%p, major=%u, minor=%u",mydev,major,pg_minor);429430cdev_init(&mydev->cdev, &pg_fops);431mydev->cdev.owner = THIS_MODULE;432result = cdev_add(&mydev->cdev, devno, 1);433if (result)434{435DebugPrint("cdev_add fault");436spin_lock(&module_lock);437dev_info[mydev->index].bUsed = FALSE;438spin_unlock(&module_lock);439kfree(mydev);440return result;441}442443pci_set_drvdata(pdev, mydev);444445result = pci_enable_device(mydev->pdev);446if (result<0)447{448DbgFunPrint("pci_enable_device fail");449return result;450}451452result = pci_request_regions(mydev->pdev, MODULENAME);453if (result<0)454{455DbgFunPrint("pci_request_regions fail");456goto error_2;457}458459pci_set_master(mydev->pdev);460461if (mmio) {462mydev->base_phyaddr = mmio;463} else {464switch(id->device) {465case 0x8167:466case 0x8169:467mydev->base_phyaddr = pci_resource_start(mydev->pdev, 1);468break;469default:470mydev->base_phyaddr = pci_resource_start(mydev->pdev, 2);471break;472}473}474475if (!mydev->base_phyaddr) {476DbgFunPrint("Invalid phyaddress");477result = -EFAULT;478goto error_1;479}480mydev->deviceID = id->device;481mydev->offset = mydev->base_phyaddr & ((1 << PAGE_SHIFT) - 1);482DbgFunPrint("ID=0x%04x base_phyaddr=0x%08x, offset=0x%08x",483mydev->deviceID , (DWORD)mydev->base_phyaddr,484mydev->offset);485486return 0;487488error_1:489pci_release_regions(mydev->pdev);490error_2:491pci_disable_device(mydev->pdev);492cdev_del(&mydev->cdev);493kfree(mydev);494return result;495}496497static void __devexit pgdrv_remove(struct pci_dev *pdev)498{499PPGDEV mydev;500501mydev = pci_get_drvdata(pdev);502DbgFunPrint("mydev=%p",mydev);503504mydev->base_phyaddr = 0;505pci_release_regions(pdev);506pci_disable_device(pdev);507508cdev_del(&mydev->cdev);509spin_lock(&module_lock);510dev_info[mydev->index].bUsed = FALSE;511spin_unlock(&module_lock);512kfree(mydev);513pci_set_drvdata(pdev, NULL);514atomic_dec(&dev_num);515}516517static struct pci_device_id pgdrv_id_table[] = {518{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8125), },519{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), },520{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8161), },521{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8162), },522{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), },523{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), },524{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), },525{0,},526};527528MODULE_DEVICE_TABLE(pci, pgdrv_id_table);529530static struct pci_driver pgdrv_pci_driver = {531.name = MODULENAME,532.id_table = pgdrv_id_table,533.probe = pgdrv_prob,534.remove = __devexit_p(pgdrv_remove),535};536537static int __init pgdrv_init(void)538{539int result, i;540dev_t devno;541542memset(dev_info, 0, sizeof(dev_info));543atomic_set(&dev_num,0);544spin_lock_init(&module_lock);545546if (!major)547{548result = alloc_chrdev_region(&devno, 0, MAX_DEV_NUM, MODULENAME);549major = MAJOR(devno);550}551else552{553devno = MKDEV(major, 0);554result = register_chrdev_region(devno, MAX_DEV_NUM, MODULENAME);555}556557if (result < 0)558{559DebugPrint("Can't get major %d", major);560return result;561}562DbgFunPrint("Major : %d",major);563564for (i=0; i<MAX_DEV_NUM; i++)565{566dev_info[i].devno = MKDEV(major, i);567}568569return pci_register_driver(&pgdrv_pci_driver);570}571572static void __exit pgdrv_exit(void)573{574DbgFunPrint();575pci_unregister_driver(&pgdrv_pci_driver);576unregister_chrdev_region(MKDEV(major, 0), MAX_DEV_NUM);577}578579module_init(pgdrv_init);580module_exit(pgdrv_exit);581582MODULE_LICENSE("GPL");583MODULE_AUTHOR("Network Interface Controllers crew <[email protected]>");584MODULE_VERSION("1.00.00");585MODULE_DESCRIPTION("RealTek driver of Ethernet PG tool");586587588