cregit-Linux how code gets into the kernel

Release 4.11 drivers/fmc/fmc-chardev.c

Directory: drivers/fmc
/*
 * Copyright (C) 2012 CERN (www.cern.ch)
 * Author: Alessandro Rubini <rubini@gnudd.com>
 *
 * Released according to the GNU GPL, version 2 or any later version.
 *
 * This work is part of the White Rabbit project, a research effort led
 * by CERN, the European Institute for Nuclear Research.
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/spinlock.h>
#include <linux/fmc.h>
#include <linux/uaccess.h>

static LIST_HEAD(fc_devices);
static DEFINE_SPINLOCK(fc_lock);


struct fc_instance {
	
struct list_head list;
	
struct fmc_device *fmc;
	
struct miscdevice misc;
};

/* at open time, we must identify our device */

static int fc_open(struct inode *ino, struct file *f) { struct fmc_device *fmc; struct fc_instance *fc; int minor = iminor(ino); list_for_each_entry(fc, &fc_devices, list) if (fc->misc.minor == minor) break; if (fc->misc.minor != minor) return -ENODEV; fmc = fc->fmc; if (try_module_get(fmc->owner) == 0) return -ENODEV; f->private_data = fmc; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alessandro Rubini97100.00%1100.00%
Total97100.00%1100.00%


static int fc_release(struct inode *ino, struct file *f) { struct fmc_device *fmc = f->private_data; module_put(fmc->owner); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alessandro Rubini35100.00%1100.00%
Total35100.00%1100.00%

/* read and write are simple after the default llseek has been used */
static ssize_t fc_read(struct file *f, char __user *buf, size_t count, loff_t *offp) { struct fmc_device *fmc = f->private_data; unsigned long addr; uint32_t val; if (count < sizeof(val)) return -EINVAL; count = sizeof(val); addr = *offp; if (addr > fmc->memlen) return -ESPIPE; /* Illegal seek */ val = fmc_readl(fmc, addr); if (copy_to_user(buf, &val, count)) return -EFAULT; *offp += count; return count; }

Contributors

PersonTokensPropCommitsCommitProp
Alessandro Rubini110100.00%1100.00%
Total110100.00%1100.00%


static ssize_t fc_write(struct file *f, const char __user *buf, size_t count, loff_t *offp) { struct fmc_device *fmc = f->private_data; unsigned long addr; uint32_t val; if (count < sizeof(val)) return -EINVAL; count = sizeof(val); addr = *offp; if (addr > fmc->memlen) return -ESPIPE; /* Illegal seek */ if (copy_from_user(&val, buf, count)) return -EFAULT; fmc_writel(fmc, val, addr); *offp += count; return count; }

Contributors

PersonTokensPropCommitsCommitProp
Alessandro Rubini111100.00%1100.00%
Total111100.00%1100.00%

static const struct file_operations fc_fops = { .owner = THIS_MODULE, .open = fc_open, .release = fc_release, .llseek = generic_file_llseek, .read = fc_read, .write = fc_write, }; /* Device part .. */ static int fc_probe(struct fmc_device *fmc); static int fc_remove(struct fmc_device *fmc); static struct fmc_driver fc_drv = { .version = FMC_VERSION, .driver.name = KBUILD_MODNAME, .probe = fc_probe, .remove = fc_remove, /* no table: we want to match everything */ }; /* We accept the generic busid parameter */ FMC_PARAM_BUSID(fc_drv); /* probe and remove must allocate and release a misc device */
static int fc_probe(struct fmc_device *fmc) { int ret; int index = 0; struct fc_instance *fc; if (fmc->op->validate) index = fmc->op->validate(fmc, &fc_drv); if (index < 0) return -EINVAL; /* not our device: invalid */ /* Create a char device: we want to create it anew */ fc = kzalloc(sizeof(*fc), GFP_KERNEL); if (!fc) return -ENOMEM; fc->fmc = fmc; fc->misc.minor = MISC_DYNAMIC_MINOR; fc->misc.fops = &fc_fops; fc->misc.name = kstrdup(dev_name(&fmc->dev), GFP_KERNEL); ret = misc_register(&fc->misc); if (ret < 0) goto out; spin_lock(&fc_lock); list_add(&fc->list, &fc_devices); spin_unlock(&fc_lock); dev_info(&fc->fmc->dev, "Created misc device \"%s\"\n", fc->misc.name); return 0; out: kfree(fc->misc.name); kfree(fc); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Alessandro Rubini17585.78%266.67%
Dan Carpenter2914.22%133.33%
Total204100.00%3100.00%


static int fc_remove(struct fmc_device *fmc) { struct fc_instance *fc; list_for_each_entry(fc, &fc_devices, list) if (fc->fmc == fmc) break; if (fc->fmc != fmc) { dev_err(&fmc->dev, "remove called but not found\n"); return -ENODEV; } spin_lock(&fc_lock); list_del(&fc->list); spin_unlock(&fc_lock); misc_deregister(&fc->misc); kfree(fc->misc.name); kfree(fc); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alessandro Rubini102100.00%2100.00%
Total102100.00%2100.00%


static int fc_init(void) { int ret; ret = fmc_driver_register(&fc_drv); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Alessandro Rubini22100.00%1100.00%
Total22100.00%1100.00%


static void fc_exit(void) { fmc_driver_unregister(&fc_drv); }

Contributors

PersonTokensPropCommitsCommitProp
Alessandro Rubini14100.00%1100.00%
Total14100.00%1100.00%

module_init(fc_init); module_exit(fc_exit); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Alessandro Rubini83896.66%266.67%
Dan Carpenter293.34%133.33%
Total867100.00%3100.00%
Directory: drivers/fmc
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.