Blame view
fs/char_dev.c
13.3 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 |
/* * linux/fs/char_dev.c * * Copyright (C) 1991, 1992 Linus Torvalds */ |
1da177e4c Linux-2.6.12-rc2 |
6 7 |
#include <linux/init.h> #include <linux/fs.h> |
b446b60e4 [PATCH] rework re... |
8 |
#include <linux/kdev_t.h> |
1da177e4c Linux-2.6.12-rc2 |
9 10 11 12 13 14 |
#include <linux/slab.h> #include <linux/string.h> #include <linux/major.h> #include <linux/errno.h> #include <linux/module.h> |
68eef3b47 [PATCH] Simplify ... |
15 |
#include <linux/seq_file.h> |
1da177e4c Linux-2.6.12-rc2 |
16 17 18 19 |
#include <linux/kobject.h> #include <linux/kobj_map.h> #include <linux/cdev.h> |
58383af62 [PATCH] kobj_map ... |
20 |
#include <linux/mutex.h> |
5da6185bc [PATCH] NOMMU: Se... |
21 |
#include <linux/backing-dev.h> |
31d1d48e1 Fix init ordering... |
22 |
#include <linux/tty.h> |
1da177e4c Linux-2.6.12-rc2 |
23 |
|
07f3f05c1 [PATCH] BLOCK: Mo... |
24 |
#include "internal.h" |
1da177e4c Linux-2.6.12-rc2 |
25 26 |
static struct kobj_map *cdev_map; |
58383af62 [PATCH] kobj_map ... |
27 |
static DEFINE_MUTEX(chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
28 29 30 31 32 33 |
static struct char_device_struct { struct char_device_struct *next; unsigned int major; unsigned int baseminor; int minorct; |
7170be5f5 [PATCH] convert /... |
34 |
char name[64]; |
1da177e4c Linux-2.6.12-rc2 |
35 |
struct cdev *cdev; /* will die */ |
68eef3b47 [PATCH] Simplify ... |
36 |
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE]; |
1da177e4c Linux-2.6.12-rc2 |
37 38 |
/* index in the above */ |
e61eb2e93 fs/block: type si... |
39 |
static inline int major_to_index(unsigned major) |
1da177e4c Linux-2.6.12-rc2 |
40 |
{ |
68eef3b47 [PATCH] Simplify ... |
41 |
return major % CHRDEV_MAJOR_HASH_SIZE; |
7170be5f5 [PATCH] convert /... |
42 |
} |
68eef3b47 [PATCH] Simplify ... |
43 |
#ifdef CONFIG_PROC_FS |
7170be5f5 [PATCH] convert /... |
44 |
|
68eef3b47 [PATCH] Simplify ... |
45 |
void chrdev_show(struct seq_file *f, off_t offset) |
7170be5f5 [PATCH] convert /... |
46 47 |
{ struct char_device_struct *cd; |
7170be5f5 [PATCH] convert /... |
48 |
|
68eef3b47 [PATCH] Simplify ... |
49 50 51 52 53 54 |
if (offset < CHRDEV_MAJOR_HASH_SIZE) { mutex_lock(&chrdevs_lock); for (cd = chrdevs[offset]; cd; cd = cd->next) seq_printf(f, "%3d %s ", cd->major, cd->name); mutex_unlock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
55 |
} |
7170be5f5 [PATCH] convert /... |
56 |
} |
68eef3b47 [PATCH] Simplify ... |
57 |
#endif /* CONFIG_PROC_FS */ |
1da177e4c Linux-2.6.12-rc2 |
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
/* * Register a single major with a specified minor range. * * If major == 0 this functions will dynamically allocate a major and return * its number. * * If major > 0 this function will attempt to reserve the passed range of * minors and will return zero on success. * * Returns a -ve errno on failure. */ static struct char_device_struct * __register_chrdev_region(unsigned int major, unsigned int baseminor, int minorct, const char *name) { struct char_device_struct *cd, **cp; int ret = 0; int i; |
11b0b5abb [PATCH] use kzall... |
77 |
cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
78 79 |
if (cd == NULL) return ERR_PTR(-ENOMEM); |
58383af62 [PATCH] kobj_map ... |
80 |
mutex_lock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
81 82 83 84 85 86 87 88 89 90 91 92 93 |
/* temporary */ if (major == 0) { for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) { if (chrdevs[i] == NULL) break; } if (i == 0) { ret = -EBUSY; goto out; } major = i; |
1da177e4c Linux-2.6.12-rc2 |
94 95 96 97 98 |
} cd->major = major; cd->baseminor = baseminor; cd->minorct = minorct; |
8c4018884 fs: fix name over... |
99 |
strlcpy(cd->name, name, sizeof(cd->name)); |
1da177e4c Linux-2.6.12-rc2 |
100 101 102 103 104 |
i = major_to_index(major); for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) if ((*cp)->major > major || |
01d553d0f [PATCH] Chardev c... |
105 106 107 |
((*cp)->major == major && (((*cp)->baseminor >= baseminor) || ((*cp)->baseminor + (*cp)->minorct > baseminor)))) |
1da177e4c Linux-2.6.12-rc2 |
108 |
break; |
01d553d0f [PATCH] Chardev c... |
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
/* Check for overlapping minor ranges. */ if (*cp && (*cp)->major == major) { int old_min = (*cp)->baseminor; int old_max = (*cp)->baseminor + (*cp)->minorct - 1; int new_min = baseminor; int new_max = baseminor + minorct - 1; /* New driver overlaps from the left. */ if (new_max >= old_min && new_max <= old_max) { ret = -EBUSY; goto out; } /* New driver overlaps from the right. */ if (new_min <= old_max && new_min >= old_min) { ret = -EBUSY; goto out; } |
1da177e4c Linux-2.6.12-rc2 |
128 |
} |
01d553d0f [PATCH] Chardev c... |
129 |
|
1da177e4c Linux-2.6.12-rc2 |
130 131 |
cd->next = *cp; *cp = cd; |
58383af62 [PATCH] kobj_map ... |
132 |
mutex_unlock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
133 134 |
return cd; out: |
58383af62 [PATCH] kobj_map ... |
135 |
mutex_unlock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
136 137 138 139 140 141 142 143 144 |
kfree(cd); return ERR_PTR(ret); } static struct char_device_struct * __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) { struct char_device_struct *cd = NULL, **cp; int i = major_to_index(major); |
58383af62 [PATCH] kobj_map ... |
145 |
mutex_lock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
146 147 148 149 150 151 152 153 154 |
for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) if ((*cp)->major == major && (*cp)->baseminor == baseminor && (*cp)->minorct == minorct) break; if (*cp) { cd = *cp; *cp = cd->next; } |
58383af62 [PATCH] kobj_map ... |
155 |
mutex_unlock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
156 157 |
return cd; } |
cf3e43dbe [PATCH] cdev docu... |
158 159 160 161 162 163 164 165 166 |
/** * register_chrdev_region() - register a range of device numbers * @from: the first in the desired range of device numbers; must include * the major number. * @count: the number of consecutive device numbers required * @name: the name of the device or driver. * * Return value is zero on success, a negative error code on failure. */ |
1da177e4c Linux-2.6.12-rc2 |
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
int register_chrdev_region(dev_t from, unsigned count, const char *name) { struct char_device_struct *cd; dev_t to = from + count; dev_t n, next; for (n = from; n < to; n = next) { next = MKDEV(MAJOR(n)+1, 0); if (next > to) next = to; cd = __register_chrdev_region(MAJOR(n), MINOR(n), next - n, name); if (IS_ERR(cd)) goto fail; } return 0; fail: to = n; for (n = from; n < to; n = next) { next = MKDEV(MAJOR(n)+1, 0); kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); } return PTR_ERR(cd); } |
cf3e43dbe [PATCH] cdev docu... |
191 192 193 194 195 196 197 198 199 200 201 |
/** * alloc_chrdev_region() - register a range of char device numbers * @dev: output parameter for first assigned number * @baseminor: first of the requested range of minor numbers * @count: the number of minor numbers required * @name: the name of the associated device or driver * * Allocates a range of char device numbers. The major number will be * chosen dynamically, and returned (along with the first minor number) * in @dev. Returns zero or a negative error code. */ |
1da177e4c Linux-2.6.12-rc2 |
202 203 204 205 206 207 208 209 210 211 |
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name) { struct char_device_struct *cd; cd = __register_chrdev_region(0, baseminor, count, name); if (IS_ERR(cd)) return PTR_ERR(cd); *dev = MKDEV(cd->major, cd->baseminor); return 0; } |
d247e2c66 [PATCH] add funct... |
212 |
/** |
1905b1bfc chrdev: implement... |
213 |
* __register_chrdev() - create and register a cdev occupying a range of minors |
d247e2c66 [PATCH] add funct... |
214 |
* @major: major device number or 0 for dynamic allocation |
1905b1bfc chrdev: implement... |
215 216 |
* @baseminor: first of the requested range of minor numbers * @count: the number of minor numbers required |
d247e2c66 [PATCH] add funct... |
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
* @name: name of this range of devices * @fops: file operations associated with this devices * * If @major == 0 this functions will dynamically allocate a major and return * its number. * * If @major > 0 this function will attempt to reserve a device with the given * major number and will return zero on success. * * Returns a -ve errno on failure. * * The name of this device has nothing to do with the name of the device in * /dev. It only helps to keep track of the different owners of devices. If * your module name has only one type of devices it's ok to use e.g. the name * of the module here. |
d247e2c66 [PATCH] add funct... |
232 |
*/ |
1905b1bfc chrdev: implement... |
233 234 235 |
int __register_chrdev(unsigned int major, unsigned int baseminor, unsigned int count, const char *name, const struct file_operations *fops) |
1da177e4c Linux-2.6.12-rc2 |
236 237 238 |
{ struct char_device_struct *cd; struct cdev *cdev; |
1da177e4c Linux-2.6.12-rc2 |
239 |
int err = -ENOMEM; |
1905b1bfc chrdev: implement... |
240 |
cd = __register_chrdev_region(major, baseminor, count, name); |
1da177e4c Linux-2.6.12-rc2 |
241 242 |
if (IS_ERR(cd)) return PTR_ERR(cd); |
1ff97647f char_dev.c: fix u... |
243 |
|
1da177e4c Linux-2.6.12-rc2 |
244 245 246 247 248 249 250 |
cdev = cdev_alloc(); if (!cdev) goto out2; cdev->owner = fops->owner; cdev->ops = fops; kobject_set_name(&cdev->kobj, "%s", name); |
1ff97647f char_dev.c: fix u... |
251 |
|
1905b1bfc chrdev: implement... |
252 |
err = cdev_add(cdev, MKDEV(cd->major, baseminor), count); |
1da177e4c Linux-2.6.12-rc2 |
253 254 255 256 257 258 259 260 261 |
if (err) goto out; cd->cdev = cdev; return major ? 0 : cd->major; out: kobject_put(&cdev->kobj); out2: |
1905b1bfc chrdev: implement... |
262 |
kfree(__unregister_chrdev_region(cd->major, baseminor, count)); |
1da177e4c Linux-2.6.12-rc2 |
263 264 |
return err; } |
cf3e43dbe [PATCH] cdev docu... |
265 266 267 268 269 270 271 272 273 |
/** * unregister_chrdev_region() - return a range of device numbers * @from: the first in the range of numbers to unregister * @count: the number of device numbers to unregister * * This function will unregister a range of @count device numbers, * starting with @from. The caller should normally be the one who * allocated those numbers in the first place... */ |
1da177e4c Linux-2.6.12-rc2 |
274 275 276 277 278 279 280 281 282 283 284 285 |
void unregister_chrdev_region(dev_t from, unsigned count) { dev_t to = from + count; dev_t n, next; for (n = from; n < to; n = next) { next = MKDEV(MAJOR(n)+1, 0); if (next > to) next = to; kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); } } |
1905b1bfc chrdev: implement... |
286 287 288 289 290 291 292 293 294 295 296 297 298 |
/** * __unregister_chrdev - unregister and destroy a cdev * @major: major device number * @baseminor: first of the range of minor numbers * @count: the number of minor numbers this cdev is occupying * @name: name of this range of devices * * Unregister and destroy the cdev occupying the region described by * @major, @baseminor and @count. This function undoes what * __register_chrdev() did. */ void __unregister_chrdev(unsigned int major, unsigned int baseminor, unsigned int count, const char *name) |
1da177e4c Linux-2.6.12-rc2 |
299 300 |
{ struct char_device_struct *cd; |
1905b1bfc chrdev: implement... |
301 302 |
cd = __unregister_chrdev_region(major, baseminor, count); |
1da177e4c Linux-2.6.12-rc2 |
303 304 305 |
if (cd && cd->cdev) cdev_del(cd->cdev); kfree(cd); |
1da177e4c Linux-2.6.12-rc2 |
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
} static DEFINE_SPINLOCK(cdev_lock); static struct kobject *cdev_get(struct cdev *p) { struct module *owner = p->owner; struct kobject *kobj; if (owner && !try_module_get(owner)) return NULL; kobj = kobject_get(&p->kobj); if (!kobj) module_put(owner); return kobj; } void cdev_put(struct cdev *p) { if (p) { |
7da6844cf [PATCH] cdev: cde... |
326 |
struct module *owner = p->owner; |
1da177e4c Linux-2.6.12-rc2 |
327 |
kobject_put(&p->kobj); |
7da6844cf [PATCH] cdev: cde... |
328 |
module_put(owner); |
1da177e4c Linux-2.6.12-rc2 |
329 330 331 332 333 334 |
} } /* * Called every time a character special file is opened */ |
922f9cfa7 fs/char_dev.c: ch... |
335 |
static int chrdev_open(struct inode *inode, struct file *filp) |
1da177e4c Linux-2.6.12-rc2 |
336 |
{ |
e84f9e57b consolidate the r... |
337 |
const struct file_operations *fops; |
1da177e4c Linux-2.6.12-rc2 |
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
struct cdev *p; struct cdev *new = NULL; int ret = 0; spin_lock(&cdev_lock); p = inode->i_cdev; if (!p) { struct kobject *kobj; int idx; spin_unlock(&cdev_lock); kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); if (!kobj) return -ENXIO; new = container_of(kobj, struct cdev, kobj); spin_lock(&cdev_lock); |
a30427d92 Add a comment in ... |
353 354 |
/* Check i_cdev again in case somebody beat us to it while we dropped the lock. */ |
1da177e4c Linux-2.6.12-rc2 |
355 356 357 |
p = inode->i_cdev; if (!p) { inode->i_cdev = p = new; |
1da177e4c Linux-2.6.12-rc2 |
358 359 360 361 362 363 364 365 366 367 |
list_add(&inode->i_devices, &p->list); new = NULL; } else if (!cdev_get(p)) ret = -ENXIO; } else if (!cdev_get(p)) ret = -ENXIO; spin_unlock(&cdev_lock); cdev_put(new); if (ret) return ret; |
a518ab932 [PATCH] tidy up c... |
368 369 |
ret = -ENXIO; |
e84f9e57b consolidate the r... |
370 371 |
fops = fops_get(p->ops); if (!fops) |
a518ab932 [PATCH] tidy up c... |
372 |
goto out_cdev_put; |
e84f9e57b consolidate the r... |
373 |
replace_fops(filp, fops); |
a518ab932 [PATCH] tidy up c... |
374 |
if (filp->f_op->open) { |
1ff97647f char_dev.c: fix u... |
375 |
ret = filp->f_op->open(inode, filp); |
a518ab932 [PATCH] tidy up c... |
376 377 378 379 380 381 382 383 |
if (ret) goto out_cdev_put; } return 0; out_cdev_put: cdev_put(p); |
1da177e4c Linux-2.6.12-rc2 |
384 385 386 387 388 389 390 391 392 393 |
return ret; } void cd_forget(struct inode *inode) { spin_lock(&cdev_lock); list_del_init(&inode->i_devices); inode->i_cdev = NULL; spin_unlock(&cdev_lock); } |
75c96f858 [PATCH] make some... |
394 |
static void cdev_purge(struct cdev *cdev) |
1da177e4c Linux-2.6.12-rc2 |
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
{ spin_lock(&cdev_lock); while (!list_empty(&cdev->list)) { struct inode *inode; inode = container_of(cdev->list.next, struct inode, i_devices); list_del_init(&inode->i_devices); inode->i_cdev = NULL; } spin_unlock(&cdev_lock); } /* * Dummy default file-operations: the only thing this does * is contain the open that then fills in the correct operations * depending on the special file... */ |
4b6f5d20b [PATCH] Make most... |
411 |
const struct file_operations def_chr_fops = { |
1da177e4c Linux-2.6.12-rc2 |
412 |
.open = chrdev_open, |
6038f373a llseek: automatic... |
413 |
.llseek = noop_llseek, |
1da177e4c Linux-2.6.12-rc2 |
414 415 416 417 418 419 420 421 422 423 424 425 426 |
}; static struct kobject *exact_match(dev_t dev, int *part, void *data) { struct cdev *p = data; return &p->kobj; } static int exact_lock(dev_t dev, void *data) { struct cdev *p = data; return cdev_get(p) ? 0 : -1; } |
cf3e43dbe [PATCH] cdev docu... |
427 428 429 430 431 432 433 434 435 436 |
/** * cdev_add() - add a char device to the system * @p: the cdev structure for the device * @dev: the first device number for which this device is responsible * @count: the number of consecutive minor numbers corresponding to this * device * * cdev_add() adds the device represented by @p to the system, making it * live immediately. A negative error code is returned on failure. */ |
1da177e4c Linux-2.6.12-rc2 |
437 438 |
int cdev_add(struct cdev *p, dev_t dev, unsigned count) { |
2f0157f13 char_dev: pin par... |
439 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
440 441 |
p->dev = dev; p->count = count; |
2f0157f13 char_dev: pin par... |
442 443 444 445 446 447 448 449 450 |
error = kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p); if (error) return error; kobject_get(p->kobj.parent); return 0; |
1da177e4c Linux-2.6.12-rc2 |
451 452 453 454 455 456 |
} static void cdev_unmap(dev_t dev, unsigned count) { kobj_unmap(cdev_map, dev, count); } |
cf3e43dbe [PATCH] cdev docu... |
457 458 459 460 461 462 463 |
/** * cdev_del() - remove a cdev from the system * @p: the cdev structure to be removed * * cdev_del() removes @p from the system, possibly freeing the structure * itself. */ |
1da177e4c Linux-2.6.12-rc2 |
464 465 466 467 468 469 470 471 472 473 |
void cdev_del(struct cdev *p) { cdev_unmap(p->dev, p->count); kobject_put(&p->kobj); } static void cdev_default_release(struct kobject *kobj) { struct cdev *p = container_of(kobj, struct cdev, kobj); |
2f0157f13 char_dev: pin par... |
474 |
struct kobject *parent = kobj->parent; |
1da177e4c Linux-2.6.12-rc2 |
475 |
cdev_purge(p); |
2f0157f13 char_dev: pin par... |
476 |
kobject_put(parent); |
1da177e4c Linux-2.6.12-rc2 |
477 478 479 480 481 |
} static void cdev_dynamic_release(struct kobject *kobj) { struct cdev *p = container_of(kobj, struct cdev, kobj); |
2f0157f13 char_dev: pin par... |
482 |
struct kobject *parent = kobj->parent; |
1da177e4c Linux-2.6.12-rc2 |
483 484 |
cdev_purge(p); kfree(p); |
2f0157f13 char_dev: pin par... |
485 |
kobject_put(parent); |
1da177e4c Linux-2.6.12-rc2 |
486 487 488 489 490 491 492 493 494 |
} static struct kobj_type ktype_cdev_default = { .release = cdev_default_release, }; static struct kobj_type ktype_cdev_dynamic = { .release = cdev_dynamic_release, }; |
cf3e43dbe [PATCH] cdev docu... |
495 496 497 498 499 |
/** * cdev_alloc() - allocate a cdev structure * * Allocates and returns a cdev structure, or NULL on failure. */ |
1da177e4c Linux-2.6.12-rc2 |
500 501 |
struct cdev *cdev_alloc(void) { |
11b0b5abb [PATCH] use kzall... |
502 |
struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
503 |
if (p) { |
1da177e4c Linux-2.6.12-rc2 |
504 |
INIT_LIST_HEAD(&p->list); |
f9cb074bf Kobject: rename k... |
505 |
kobject_init(&p->kobj, &ktype_cdev_dynamic); |
1da177e4c Linux-2.6.12-rc2 |
506 507 508 |
} return p; } |
cf3e43dbe [PATCH] cdev docu... |
509 510 511 512 513 514 515 516 |
/** * cdev_init() - initialize a cdev structure * @cdev: the structure to initialize * @fops: the file_operations for this device * * Initializes @cdev, remembering @fops, making it ready to add to the * system with cdev_add(). */ |
99ac48f54 [PATCH] mark f_op... |
517 |
void cdev_init(struct cdev *cdev, const struct file_operations *fops) |
1da177e4c Linux-2.6.12-rc2 |
518 519 520 |
{ memset(cdev, 0, sizeof *cdev); INIT_LIST_HEAD(&cdev->list); |
f9cb074bf Kobject: rename k... |
521 |
kobject_init(&cdev->kobj, &ktype_cdev_default); |
1da177e4c Linux-2.6.12-rc2 |
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 |
cdev->ops = fops; } static struct kobject *base_probe(dev_t dev, int *part, void *data) { if (request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev)) > 0) /* Make old-style 2.4 aliases work */ request_module("char-major-%d", MAJOR(dev)); return NULL; } void __init chrdev_init(void) { cdev_map = kobj_map_init(base_probe, &chrdevs_lock); } /* Let modules do char dev stuff */ EXPORT_SYMBOL(register_chrdev_region); EXPORT_SYMBOL(unregister_chrdev_region); EXPORT_SYMBOL(alloc_chrdev_region); EXPORT_SYMBOL(cdev_init); EXPORT_SYMBOL(cdev_alloc); EXPORT_SYMBOL(cdev_del); EXPORT_SYMBOL(cdev_add); |
1905b1bfc chrdev: implement... |
547 548 |
EXPORT_SYMBOL(__register_chrdev); EXPORT_SYMBOL(__unregister_chrdev); |