Blame view
drivers/char/misc.c
6.82 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
/* * linux/drivers/char/misc.c * * Generic misc open routine by Johan Myreen * * Based on code from Linus * * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's * changes incorporated into 0.97pl4 * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92) * See busmouse.c for particulars. * * Made things a lot mode modular - easy to compile in just one or two * of the misc drivers, as they are now completely independent. Linus. * * Support for loadable modules. 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk> * * Fixed a failing symbol register to free the device registration * Alan Cox <alan@lxorguk.ukuu.org.uk> 21-Jan-96 * * Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96 * * Renamed to misc and miscdevice to be more accurate. Alan Cox 26-Mar-96 * * Handling of mouse minor numbers for kerneld: * Idea by Jacques Gelinas <jack@solucorp.qc.ca>, * adapted by Bjorn Ekwall <bj0rn@blox.se> * corrected by Alan Cox <alan@lxorguk.ukuu.org.uk> * * Changes for kmod (from kerneld): * Cyrus Durgin <cider@speakeasy.org> * * Added devfs support. Richard Gooch <rgooch@atnf.csiro.au> 10-Jan-1998 */ #include <linux/module.h> |
1da177e4c Linux-2.6.12-rc2 |
37 38 39 40 41 42 43 |
#include <linux/fs.h> #include <linux/errno.h> #include <linux/miscdevice.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/slab.h> |
0e82d5b61 use mutex instead... |
44 |
#include <linux/mutex.h> |
1da177e4c Linux-2.6.12-rc2 |
45 46 |
#include <linux/proc_fs.h> #include <linux/seq_file.h> |
1da177e4c Linux-2.6.12-rc2 |
47 48 49 50 51 |
#include <linux/stat.h> #include <linux/init.h> #include <linux/device.h> #include <linux/tty.h> #include <linux/kmod.h> |
309c4551c misc: cdev lock_k... |
52 |
#include <linux/smp_lock.h> |
1da177e4c Linux-2.6.12-rc2 |
53 54 55 56 57 |
/* * Head entry for the doubly linked miscdevice list */ static LIST_HEAD(misc_list); |
0e82d5b61 use mutex instead... |
58 |
static DEFINE_MUTEX(misc_mtx); |
1da177e4c Linux-2.6.12-rc2 |
59 60 61 62 63 64 |
/* * Assigned numbers, used for dynamic minors */ #define DYNAMIC_MINORS 64 /* like dynamic majors */ static unsigned char misc_minors[DYNAMIC_MINORS / 8]; |
1da177e4c Linux-2.6.12-rc2 |
65 |
extern int pmu_device_init(void); |
1da177e4c Linux-2.6.12-rc2 |
66 67 68 69 |
#ifdef CONFIG_PROC_FS static void *misc_seq_start(struct seq_file *seq, loff_t *pos) { |
0e82d5b61 use mutex instead... |
70 |
mutex_lock(&misc_mtx); |
46c65b71e Make /proc/misc u... |
71 |
return seq_list_start(&misc_list, *pos); |
1da177e4c Linux-2.6.12-rc2 |
72 73 74 75 |
} static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos) { |
46c65b71e Make /proc/misc u... |
76 |
return seq_list_next(v, &misc_list, pos); |
1da177e4c Linux-2.6.12-rc2 |
77 78 79 80 |
} static void misc_seq_stop(struct seq_file *seq, void *v) { |
0e82d5b61 use mutex instead... |
81 |
mutex_unlock(&misc_mtx); |
1da177e4c Linux-2.6.12-rc2 |
82 83 84 85 |
} static int misc_seq_show(struct seq_file *seq, void *v) { |
46c65b71e Make /proc/misc u... |
86 |
const struct miscdevice *p = list_entry(v, struct miscdevice, list); |
1da177e4c Linux-2.6.12-rc2 |
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
seq_printf(seq, "%3i %s ", p->minor, p->name ? p->name : ""); return 0; } static struct seq_operations misc_seq_ops = { .start = misc_seq_start, .next = misc_seq_next, .stop = misc_seq_stop, .show = misc_seq_show, }; static int misc_seq_open(struct inode *inode, struct file *file) { return seq_open(file, &misc_seq_ops); } |
62322d255 [PATCH] make more... |
105 |
static const struct file_operations misc_proc_fops = { |
1da177e4c Linux-2.6.12-rc2 |
106 107 108 109 110 111 112 113 114 115 116 117 118 |
.owner = THIS_MODULE, .open = misc_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; #endif static int misc_open(struct inode * inode, struct file * file) { int minor = iminor(inode); struct miscdevice *c; int err = -ENODEV; |
99ac48f54 [PATCH] mark f_op... |
119 |
const struct file_operations *old_fops, *new_fops = NULL; |
1da177e4c Linux-2.6.12-rc2 |
120 |
|
309c4551c misc: cdev lock_k... |
121 |
lock_kernel(); |
0e82d5b61 use mutex instead... |
122 |
mutex_lock(&misc_mtx); |
1da177e4c Linux-2.6.12-rc2 |
123 124 125 126 127 128 129 130 131 |
list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { new_fops = fops_get(c->fops); break; } } if (!new_fops) { |
0e82d5b61 use mutex instead... |
132 |
mutex_unlock(&misc_mtx); |
1da177e4c Linux-2.6.12-rc2 |
133 |
request_module("char-major-%d-%d", MISC_MAJOR, minor); |
0e82d5b61 use mutex instead... |
134 |
mutex_lock(&misc_mtx); |
1da177e4c Linux-2.6.12-rc2 |
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { new_fops = fops_get(c->fops); break; } } if (!new_fops) goto fail; } err = 0; old_fops = file->f_op; file->f_op = new_fops; if (file->f_op->open) { err=file->f_op->open(inode,file); if (err) { fops_put(file->f_op); file->f_op = fops_get(old_fops); } } fops_put(old_fops); fail: |
0e82d5b61 use mutex instead... |
158 |
mutex_unlock(&misc_mtx); |
309c4551c misc: cdev lock_k... |
159 |
unlock_kernel(); |
1da177e4c Linux-2.6.12-rc2 |
160 161 |
return err; } |
ca8eca688 [PATCH] class: co... |
162 |
static struct class *misc_class; |
1da177e4c Linux-2.6.12-rc2 |
163 |
|
62322d255 [PATCH] make more... |
164 |
static const struct file_operations misc_fops = { |
1da177e4c Linux-2.6.12-rc2 |
165 166 167 |
.owner = THIS_MODULE, .open = misc_open, }; |
1da177e4c Linux-2.6.12-rc2 |
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
/** * misc_register - register a miscellaneous device * @misc: device structure * * Register a miscellaneous device with the kernel. If the minor * number is set to %MISC_DYNAMIC_MINOR a minor number is assigned * and placed in the minor field of the structure. For other cases * the minor number requested is used. * * The structure passed is linked into the kernel and may not be * destroyed until it has been unregistered. * * A zero is returned on success and a negative errno code for * failure. */ int misc_register(struct miscdevice * misc) { struct miscdevice *c; dev_t dev; |
7c69ef797 [PATCH] devfs: Re... |
188 |
int err = 0; |
1da177e4c Linux-2.6.12-rc2 |
189 |
|
5d469ec0f [PATCH] Correct m... |
190 |
INIT_LIST_HEAD(&misc->list); |
0e82d5b61 use mutex instead... |
191 |
mutex_lock(&misc_mtx); |
1da177e4c Linux-2.6.12-rc2 |
192 193 |
list_for_each_entry(c, &misc_list, list) { if (c->minor == misc->minor) { |
0e82d5b61 use mutex instead... |
194 |
mutex_unlock(&misc_mtx); |
1da177e4c Linux-2.6.12-rc2 |
195 196 197 198 199 200 201 202 203 204 |
return -EBUSY; } } if (misc->minor == MISC_DYNAMIC_MINOR) { int i = DYNAMIC_MINORS; while (--i >= 0) if ( (misc_minors[i>>3] & (1 << (i&7))) == 0) break; if (i<0) { |
0e82d5b61 use mutex instead... |
205 |
mutex_unlock(&misc_mtx); |
1da177e4c Linux-2.6.12-rc2 |
206 207 208 209 210 211 212 |
return -EBUSY; } misc->minor = i; } if (misc->minor < DYNAMIC_MINORS) misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); |
1da177e4c Linux-2.6.12-rc2 |
213 |
dev = MKDEV(MISC_MAJOR, misc->minor); |
d40564053 Driver Core: misc... |
214 215 |
misc->this_device = device_create(misc_class, misc->parent, dev, misc, "%s", misc->name); |
94fbcded4 Driver core: chan... |
216 217 |
if (IS_ERR(misc->this_device)) { err = PTR_ERR(misc->this_device); |
1da177e4c Linux-2.6.12-rc2 |
218 219 |
goto out; } |
1da177e4c Linux-2.6.12-rc2 |
220 221 222 223 224 225 |
/* * Add it to the front, so that later devices can "override" * earlier defaults */ list_add(&misc->list, &misc_list); out: |
0e82d5b61 use mutex instead... |
226 |
mutex_unlock(&misc_mtx); |
1da177e4c Linux-2.6.12-rc2 |
227 228 229 230 |
return err; } /** |
b844eba29 PM: Remove destro... |
231 |
* misc_deregister - unregister a miscellaneous device |
1da177e4c Linux-2.6.12-rc2 |
232 233 234 235 236 237 238 |
* @misc: device to unregister * * Unregister a miscellaneous device that was previously * successfully registered with misc_register(). Success * is indicated by a zero return, a negative errno code * indicates an error. */ |
b844eba29 PM: Remove destro... |
239 |
int misc_deregister(struct miscdevice *misc) |
1da177e4c Linux-2.6.12-rc2 |
240 241 242 243 244 |
{ int i = misc->minor; if (list_empty(&misc->list)) return -EINVAL; |
0e82d5b61 use mutex instead... |
245 |
mutex_lock(&misc_mtx); |
1da177e4c Linux-2.6.12-rc2 |
246 |
list_del(&misc->list); |
b844eba29 PM: Remove destro... |
247 |
device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); |
1da177e4c Linux-2.6.12-rc2 |
248 249 250 |
if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); } |
0e82d5b61 use mutex instead... |
251 |
mutex_unlock(&misc_mtx); |
1da177e4c Linux-2.6.12-rc2 |
252 253 254 255 |
return 0; } EXPORT_SYMBOL(misc_register); |
b844eba29 PM: Remove destro... |
256 |
EXPORT_SYMBOL(misc_deregister); |
1da177e4c Linux-2.6.12-rc2 |
257 |
|
d40564053 Driver Core: misc... |
258 259 260 261 262 263 264 265 |
static char *misc_nodename(struct device *dev) { struct miscdevice *c = dev_get_drvdata(dev); if (c->devnode) return kstrdup(c->devnode, GFP_KERNEL); return NULL; } |
1da177e4c Linux-2.6.12-rc2 |
266 267 |
static int __init misc_init(void) { |
1b5022173 drivers: use non-... |
268 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
269 |
|
1b5022173 drivers: use non-... |
270 271 |
#ifdef CONFIG_PROC_FS proc_create("misc", 0, NULL, &misc_proc_fops); |
1da177e4c Linux-2.6.12-rc2 |
272 |
#endif |
ca8eca688 [PATCH] class: co... |
273 |
misc_class = class_create(THIS_MODULE, "misc"); |
1b5022173 drivers: use non-... |
274 |
err = PTR_ERR(misc_class); |
1da177e4c Linux-2.6.12-rc2 |
275 |
if (IS_ERR(misc_class)) |
1b5022173 drivers: use non-... |
276 |
goto fail_remove; |
573fc1131 [PATCH] move m68k... |
277 |
|
1b5022173 drivers: use non-... |
278 279 280 |
err = -EIO; if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) goto fail_printk; |
d40564053 Driver Core: misc... |
281 |
misc_class->nodename = misc_nodename; |
1da177e4c Linux-2.6.12-rc2 |
282 |
return 0; |
1b5022173 drivers: use non-... |
283 284 285 286 287 288 289 290 |
fail_printk: printk("unable to get major %d for misc devices ", MISC_MAJOR); class_destroy(misc_class); fail_remove: remove_proc_entry("misc", NULL); return err; |
1da177e4c Linux-2.6.12-rc2 |
291 292 |
} subsys_initcall(misc_init); |