Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.1-rc5 200 lines 4.2 kB view raw
1/* 2 * Copyright (C) 2012 CERN (www.cern.ch) 3 * Author: Alessandro Rubini <rubini@gnudd.com> 4 * 5 * Released according to the GNU GPL, version 2 or any later version. 6 * 7 * This work is part of the White Rabbit project, a research effort led 8 * by CERN, the European Institute for Nuclear Research. 9 */ 10#include <linux/module.h> 11#include <linux/init.h> 12#include <linux/list.h> 13#include <linux/slab.h> 14#include <linux/fs.h> 15#include <linux/miscdevice.h> 16#include <linux/spinlock.h> 17#include <linux/fmc.h> 18#include <linux/uaccess.h> 19 20static LIST_HEAD(fc_devices); 21static DEFINE_SPINLOCK(fc_lock); 22 23struct fc_instance { 24 struct list_head list; 25 struct fmc_device *fmc; 26 struct miscdevice misc; 27}; 28 29/* at open time, we must identify our device */ 30static int fc_open(struct inode *ino, struct file *f) 31{ 32 struct fmc_device *fmc; 33 struct fc_instance *fc; 34 int minor = iminor(ino); 35 36 list_for_each_entry(fc, &fc_devices, list) 37 if (fc->misc.minor == minor) 38 break; 39 if (fc->misc.minor != minor) 40 return -ENODEV; 41 fmc = fc->fmc; 42 if (try_module_get(fmc->owner) == 0) 43 return -ENODEV; 44 45 f->private_data = fmc; 46 return 0; 47} 48 49static int fc_release(struct inode *ino, struct file *f) 50{ 51 struct fmc_device *fmc = f->private_data; 52 module_put(fmc->owner); 53 return 0; 54} 55 56/* read and write are simple after the default llseek has been used */ 57static ssize_t fc_read(struct file *f, char __user *buf, size_t count, 58 loff_t *offp) 59{ 60 struct fmc_device *fmc = f->private_data; 61 unsigned long addr; 62 uint32_t val; 63 64 if (count < sizeof(val)) 65 return -EINVAL; 66 count = sizeof(val); 67 68 addr = *offp; 69 if (addr > fmc->memlen) 70 return -ESPIPE; /* Illegal seek */ 71 val = fmc_readl(fmc, addr); 72 if (copy_to_user(buf, &val, count)) 73 return -EFAULT; 74 *offp += count; 75 return count; 76} 77 78static ssize_t fc_write(struct file *f, const char __user *buf, size_t count, 79 loff_t *offp) 80{ 81 struct fmc_device *fmc = f->private_data; 82 unsigned long addr; 83 uint32_t val; 84 85 if (count < sizeof(val)) 86 return -EINVAL; 87 count = sizeof(val); 88 89 addr = *offp; 90 if (addr > fmc->memlen) 91 return -ESPIPE; /* Illegal seek */ 92 if (copy_from_user(&val, buf, count)) 93 return -EFAULT; 94 fmc_writel(fmc, val, addr); 95 *offp += count; 96 return count; 97} 98 99static const struct file_operations fc_fops = { 100 .owner = THIS_MODULE, 101 .open = fc_open, 102 .release = fc_release, 103 .llseek = generic_file_llseek, 104 .read = fc_read, 105 .write = fc_write, 106}; 107 108 109/* Device part .. */ 110static int fc_probe(struct fmc_device *fmc); 111static int fc_remove(struct fmc_device *fmc); 112 113static struct fmc_driver fc_drv = { 114 .version = FMC_VERSION, 115 .driver.name = KBUILD_MODNAME, 116 .probe = fc_probe, 117 .remove = fc_remove, 118 /* no table: we want to match everything */ 119}; 120 121/* We accept the generic busid parameter */ 122FMC_PARAM_BUSID(fc_drv); 123 124/* probe and remove must allocate and release a misc device */ 125static int fc_probe(struct fmc_device *fmc) 126{ 127 int ret; 128 int index = 0; 129 130 struct fc_instance *fc; 131 132 index = fmc_validate(fmc, &fc_drv); 133 if (index < 0) 134 return -EINVAL; /* not our device: invalid */ 135 136 /* Create a char device: we want to create it anew */ 137 fc = kzalloc(sizeof(*fc), GFP_KERNEL); 138 if (!fc) 139 return -ENOMEM; 140 fc->fmc = fmc; 141 fc->misc.minor = MISC_DYNAMIC_MINOR; 142 fc->misc.fops = &fc_fops; 143 fc->misc.name = kstrdup(dev_name(&fmc->dev), GFP_KERNEL); 144 145 ret = misc_register(&fc->misc); 146 if (ret < 0) 147 goto out; 148 spin_lock(&fc_lock); 149 list_add(&fc->list, &fc_devices); 150 spin_unlock(&fc_lock); 151 dev_info(&fc->fmc->dev, "Created misc device \"%s\"\n", 152 fc->misc.name); 153 return 0; 154 155out: 156 kfree(fc->misc.name); 157 kfree(fc); 158 return ret; 159} 160 161static int fc_remove(struct fmc_device *fmc) 162{ 163 struct fc_instance *fc; 164 165 list_for_each_entry(fc, &fc_devices, list) 166 if (fc->fmc == fmc) 167 break; 168 if (fc->fmc != fmc) { 169 dev_err(&fmc->dev, "remove called but not found\n"); 170 return -ENODEV; 171 } 172 173 spin_lock(&fc_lock); 174 list_del(&fc->list); 175 spin_unlock(&fc_lock); 176 misc_deregister(&fc->misc); 177 kfree(fc->misc.name); 178 kfree(fc); 179 180 return 0; 181} 182 183 184static int fc_init(void) 185{ 186 int ret; 187 188 ret = fmc_driver_register(&fc_drv); 189 return ret; 190} 191 192static void fc_exit(void) 193{ 194 fmc_driver_unregister(&fc_drv); 195} 196 197module_init(fc_init); 198module_exit(fc_exit); 199 200MODULE_LICENSE("GPL");