Skip to content
Snippets Groups Projects
Commit 8d37fd80 authored by Patrick Robbe's avatar Patrick Robbe
Browse files

Add driver files

parent c07a2d68
No related branches found
No related tags found
No related merge requests found
//p40emu``+
#define P40_FMT "P40ECSemu:%s(): "
#define PCIE40_ECS_CLASS "lhcb_pcie40_ecs_emu"
#define PCIE40_EMU
#include "ecs.h"
#include "pcie40_ioctl.h"
//static void ecs_emu_vma_open(struct vm_area_struct *vma)
//{
// printk(P40_INFO "VIRT=%lx, PHYS=%lx SIZE=%lx\n", P40_PARM, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT, vma->vm_end - vma->vm_start);
//}
//static void ecs_emu_vma_close(struct vm_area_struct *vma)
//{
// printk(P40_INFO "VIRT=%lx, PHYS=%lx SIZE=%lx\n", P40_PARM, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT, vma->vm_end - vma->vm_start);
//}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0))
static int ecs_emu_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
#else
static int ecs_emu_vma_fault(struct vm_fault *vmf)
#endif
{
struct pcie40_ecs_state *state = vma->vm_private_data;
unsigned long offset =
(unsigned long)(vmf->virtual_address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
void *ptr = NULL;
switch (iminor(vma->vm_file->f_path.dentry->d_inode)) {
case BAR0_CDEV_MINOR:
ptr = state->common->bar0_regs + offset;
break;
case BAR2_CDEV_MINOR:
ptr = state->common->bar2_regs + offset;
break;
default:
return -EINVAL;
}
vmf->page = vmalloc_to_page(ptr);
get_page(vmf->page);
//printk(P40_DIAG "fault @ 0x%08lX\n", P40_PARM, vmf->pgoff);
return 0;
}
static struct vm_operations_struct ecs_emu_vm_ops = {
//.access = generic_access_phys,
//.open = ecs_emu_vma_open,
//.close = ecs_emu_vma_close,
.fault = ecs_emu_vma_fault,
};
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
static int ecs_emu_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
#else
static long ecs_emu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
#endif //+`ecs_emu_ioctl`
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
struct inode *inode = filp->f_inode;
#endif
struct pcie40_ecs_state *state = filp->private_data;
int bar;
switch (iminor(inode)) {
case BAR0_CDEV_MINOR:
bar = 0;
break;
case BAR2_CDEV_MINOR:
bar = 2;
break;
default:
return -EINVAL;
}
//ioctl.pcie`P40_ECS_GET_BAR_SIZE`
if (cmd != P40_ECS_GET_BAR_SIZE) {
printk(P40_DIAG "invalid ioctl command\n", P40_PARM);
return -EINVAL;
}
printk(P40_INFO "ECS BAR size is %lu\n", P40_PARM, state->common->bar_size[bar]);
return state->common->bar_size[bar];
}
//+`ecs_emu_mmap`
static int ecs_emu_mmap(struct file* filp, struct vm_area_struct* vma)//;?>
{
struct pcie40_ecs_state *state = filp->private_data;
int bar;
switch (iminor(filp->f_path.dentry->d_inode)) {
case BAR0_CDEV_MINOR:
bar = 0;
break;
case BAR2_CDEV_MINOR:
bar = 2;
break;
default:
return -EINVAL;
}
vma->vm_flags |= VM_SHARED;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
printk(P40_INFO "VIRT=%lx PHYS=%lx SIZE=%lu\n", P40_PARM,
vma->vm_start, state->common->bar_start[bar], vma->vm_end - vma->vm_start);
vma->vm_ops = &ecs_emu_vm_ops;
vma->vm_private_data = state;
return 0;
}
static struct file_operations ecs_file_ops = {
.owner = THIS_MODULE,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
.ioctl = ecs_emu_ioctl,
#else
.unlocked_ioctl = ecs_emu_ioctl,
#endif
.mmap = ecs_emu_mmap,
.open = ecs_open,
.release = ecs_release,
};
int pcie40_ecs_emu_probe(struct pcie40_state *common)
{
int rc = 0;
struct pcie40_ecs_state *state = NULL;
state = kzalloc(sizeof(struct pcie40_ecs_state), GFP_KERNEL);
if (IS_ERR(state)) {
printk(P40_ERR "kzalloc()\n", P40_PARM);
rc = PTR_ERR(state);
goto err_kzalloc;
}
state->common = common;
printk(P40_DIAG "state = 0x%p\n", P40_PARM, state);
rc = alloc_chrdev_region(&(state->dev_num), P40_ECS_CDEV_BASEMINOR, P40_ECS_CDEV_COUNT, P40_DRV_NAME);
if (rc < 0) {
printk(P40_ERR "alloc_chrdev_region()\n", P40_PARM);
goto err_alloc_chrdev_region;
}
// BAR0 endpoint
if (state->common->bar_size[0]) {
rc = pcie40_setup_cdev(pcie40_ecs_class, &(state->bar0_cdev), state->dev_num, BAR0_CDEV_MINOR, 0, BAR0_CDEV_NAME, state->common->dev_id, &ecs_file_ops);
if (rc < 0) {
goto err_bar0_dev;
}
}
// BAR2 endpoint
if (state->common->bar_size[2]) {
rc = pcie40_setup_cdev(pcie40_ecs_class, &(state->bar2_cdev), state->dev_num, BAR2_CDEV_MINOR, 2, BAR2_CDEV_NAME, state->common->dev_id, &ecs_file_ops);
if (rc < 0) {
goto err_bar2_dev;
}
}
common->ecs_state = state;
return rc;
err_bar2_dev:
if (state->common->bar_size[0]) {
printk(P40_INFO "remove /dev/pcie40_%d_%s\n", P40_PARM, state->common->dev_id, BAR0_CDEV_NAME);
device_destroy(pcie40_ecs_class, MKDEV(MAJOR(state->dev_num), MINOR(state->dev_num)+BAR0_CDEV_MINOR));
}
err_bar0_dev:
unregister_chrdev_region(state->dev_num, P40_ECS_CDEV_COUNT);
err_alloc_chrdev_region:
kfree(state);
common->ecs_state = NULL;
err_kzalloc:
return rc;
}
void pcie40_ecs_emu_remove(struct pcie40_state *common)
{
struct pcie40_ecs_state *state = common->ecs_state;
printk(P40_DIAG "state = 0x%p\n", P40_PARM, state);
if (!state) {
printk(P40_ERR "no state\n", P40_PARM);
return;
}
if (state->common->bar_size[2]) {
printk(P40_INFO "remove /dev/pcie40_%d_%s\n", P40_PARM, state->common->dev_id, BAR2_CDEV_NAME);
device_destroy(pcie40_ecs_class, MKDEV(MAJOR(state->dev_num), MINOR(state->dev_num)+BAR2_CDEV_MINOR));
}
if (state->common->bar_size[0]) {
printk(P40_INFO "remove /dev/pcie40_%d_%s\n", P40_PARM, state->common->dev_id, BAR0_CDEV_NAME);
device_destroy(pcie40_ecs_class, MKDEV(MAJOR(state->dev_num), MINOR(state->dev_num)+BAR0_CDEV_MINOR));
}
unregister_chrdev_region(state->dev_num, P40_ECS_CDEV_COUNT);
kfree(state);
common->ecs_state = NULL;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment