//#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/aio.h>
#include <asm/uaccess.h>
#include "lpc_driver.h" /* local definitions */
#include <asm/io.h>
#include "comm_head.h"
#include <linux/mm.h>
int lpc_test_major = LPC_TEST_MAJOR;
int lpc_test_devs = LPC_TEST_DEVS; /* number of lpc test devices */
static int share_mem_size = 0;
module_param(lpc_test_major, int, 0);
module_param(lpc_test_devs, int, 1);
MODULE_AUTHOR("zhousl");
MODULE_LICENSE("Dual BSD/GPL");
struct lpc_test_dev *lpc_test_devices; /* allocated in lpc_test_init */
void lpc_test_cleanup(void);
/******************************
* open lpc test device
*******************************/
int lpc_test_open (struct inode *inode, struct file *filp)
{
struct lpc_test_dev *dev; /* device information */
/* Find the device */
dev = container_of(inode->i_cdev, struct lpc_test_dev, cdev);
/* and use filp->private_data to point to the device data */
filp->private_data = dev;
return 0; /* success */
}
/******************************
* close lpc test device
*******************************/
int lpc_test_release (struct inode *inode, struct file *filp)
{
return 0;
}
/*
* Data management: read and write
*/
ssize_t lpc_test_read (struct file *filp, char __user *buf, size_t count,
loff_t *f_pos)
{
struct lpc_test_dev *dev = filp->private_data; /* the first listitem */
ssize_t retval = 0;
char readDataBuf[LPC_MSG_MAX_LEN] = {0};
loff_t pos=*f_pos;
if((count > LPC_MSG_MAX_LEN) || (pos > 0x7fffffc))
{
return -EFAULT;
}
if (down_interruptible (&dev->sem))
return -ERESTARTSYS;
/*add lpc receive interface*/
printk("\e[31mread begin, read count:%ld pos:%lld\e[0m\n",count ,pos);
//memcpy(readDataBuf,dev->lpc_base+pos,count);
/*if (copy_to_user (buf, dev->lpc_base+pos, count)) {
retval = -EFAULT;
goto nothing;
}*/
if (copy_to_user (buf, dev->mmap_buf+pos, count)) {
retval = -EFAULT;
goto nothing;
}
printk("\e[31mread data:%s\e[0m\n",readDataBuf);
up (&dev->sem);
return count;
nothing:
up (&dev->sem);
return retval;
}
ssize_t lpc_test_write (struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
struct lpc_test_dev *dev = filp->private_data;
ssize_t retval = -ENOMEM; /* our most likely error */
//char writDataBuf[LPC_MSG_MAX_LEN] = {0};
loff_t pos=*f_pos;
if((count > LPC_MSG_MAX_LEN) || (pos > 0x7fffffc))
{
return -EFAULT;
}
if (down_interruptible (&dev->sem))
return -ERESTARTSYS;
printk("\e[31msend:%s, pos:%lld, count:%ld\e[0m\n",buf,pos,count);
/*if (copy_from_user (dev->lpc_base+pos, buf, count)) {
retval = -EFAULT;
goto nomem;
}*/
if (copy_from_user (dev->mmap_buf+pos, buf, count)) {
retval = -EFAULT;
goto nomem;
}
/*add lpc send interface*/
up (&dev->sem);
return count;
nomem:
up (&dev->sem);
return retval;
}
/*
* The ioctl() implementation
*/
long lpc_test_ioctl (struct file *filp,
unsigned int cmd, unsigned long arg)
{
int err = 0, ret = 0, tmp = 0;
struct lpc_test_dev *dev = filp->private_data;
/* don't even decode wrong cmds: better returning ENOTTY than EFAULT */
if (_IOC_TYPE(cmd) != LPC_IOC_MAGIC) return -ENOTTY;
if (_IOC_NR(cmd) > LPC_IOC_MAXNR) return -ENOTTY;
/*
* the type is a bitmask, and VERIFY_WRITE catches R/W
* transfers. Note that the type is user-oriented, while
* verify_area is kernel-oriented, so the concept of "read" and
* "write" is reversed
*/
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
switch(cmd) {
case LPC_IOC_SET_SPCE_CONF:
ret = __get_user(tmp, (int __user *) arg);
writel(tmp, dev->lpc_base + LPC_ADDR_CFG_REG);
printk("\e[31mset lpc addr cfg reg:0x%x\e[0m\n",tmp);
break;
case LPC_IOC_GET_SPCE_CONF:
tmp = readl(dev->lpc_base + LPC_ADDR_CFG_REG);
ret = __put_user (tmp, (int __user *) arg);
printk("\e[31mget lpc addr cfg reg:0x%x\e[0m\n",tmp);
break;
default: /* redundant, as cmd was checked against MAXNR */
return -ENOTTY;
}
return ret;
}
/*
* The "extended" operations
*/
loff_t lpc_test_llseek (struct file *filp, loff_t off, int whence)
{
struct lpc_test_dev *dev = filp->private_data;
long newpos;
switch(whence) {
case 0: /* SEEK_SET */
newpos = off;
break;
case 1: /* SEEK_CUR */
newpos = filp->f_pos + off;
break;
case 2: /* SEEK_END */
newpos = dev->size + off;
break;
default: /* can't happen */
return -EINVAL;
}
if (newpos<0) return -EINVAL;
filp->f_pos = newpos;
return newpos;
}
int lpc_test_memmap(struct file *filp, struct vm_area_struct *vma)
{
struct lpc_test_dev *dev = filp->private_data;
unsigned long offset = (((unsigned long)vma->vm_pgoff)<<PAGE_SHIFT);
//unsigned long physics = ((unsigned long)pPcieFpgaDev->pcie_fpga_msgbuf) - PAGE_OFFSET;
//unsigned long mypfn = physics>>PAGE_SHIFT;
unsigned long vmsize = PAGE_ALIGN(vma->vm_end - vma->vm_start);
unsigned long psize = (LPC_ADDR_SIZE) - offset;
/*unsigned int offset = vma->vm_pgoff<<PAGE_SHIFT;
unsigned int physics = ((unsigned int)pPcieFpgaDev->pcie_fpga_msgbuf) - PAGE_OFFSET;
unsigned int mypfn = physics>>PAGE_SHIFT;
unsigned int vmsize = vma->vm_end - vma->vm_start;
unsigned int psize = (64*1024*2) - offset;*/
printk("\e[31min memmap\e[0m\n");
printk("\e[31mpageoffset:0x%lx, pageshift:%d\e[0m\n",PAGE_OFFSET,PAGE_SHIFT);
printk("\e[31mvmsize==%ld, psize==%ld, offset==%ld\e[0m\n",vmsize, psize, offset);
printk("\e[31mphysic_pfn==0x%llx,vm_pgoff==0x%lx\e[0m\n",virt_to_phys(dev->mmap_buf) >> PAGE_SHIFT,vma->vm_pgoff);
if(vmsize > psize)
{
printk("size error, vmsize==%ld, psize==%ld, offset==%ld!\n", vmsize, psize, offset);
return -ENXIO;
}
//if(remap_pfn_range(vma, vma->vm_start, mypfn, vmsize, vma->vm_page_prot))
if(remap_pfn_range(vma, vma->vm_start, (virt_to_phys(dev->mmap_buf) >> PAGE_SHIFT), vmsize, vma->vm_page_prot))
{
printk("remap_pfn_range failed!\n");
return -EAGAIN;
}
return 0;
}
/*
* The fops
*/
struct file_operations lpc_test_fops = {
.owner = THIS_MODULE,
.llseek = lpc_test_llseek,
.read = lpc_test_read,
.write = lpc_test_write,
.unlocked_ioctl = lpc_test_ioctl,
.compat_ioctl = lpc_test_ioctl,
.open = lpc_test_open,
.release = lpc_test_release,
.mmap = lpc_test_memmap,
};
static void scullc_setup_cdev(struct lpc_test_dev *dev, int index)
{
int err, devno = MKDEV(lpc_test_major, index);
cdev_init(&dev->cdev, &lpc_test_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &lpc_test_fops;
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding lpc_test%d", err, index);
}
static unsigned char *malloc_reserved_mem(unsigned int size)
{
unsigned char *p = kzalloc(size,GFP_KERNEL);
unsigned char *tmp = p;
struct page *page;
share_mem_size = PAGE_ALIGN(size);
printk("shared mem size:%d\n",share_mem_size);
if(NULL == p)
{
printk(KERN_EMERG "<<<<<<<<<<malloc_reserved_mem kmalloc fai>>>>>>>>l\n");
return NULL;
}
for(page=vi
评论0