Blame view
fs/char_dev.c
13.8 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 |
|
5da6185bc [PATCH] NOMMU: Se... |
26 27 28 29 30 31 32 33 |
/* * capabilities for /dev/mem, /dev/kmem and similar directly mappable character * devices * - permits shared-mmap for read, write and/or exec * - does not permit private mmap in NOMMU mode (can't do COW) * - no readahead or I/O queue unplugging required */ struct backing_dev_info directly_mappable_cdev_bdi = { |
d993831fa writeback: add na... |
34 |
.name = "char", |
5da6185bc [PATCH] NOMMU: Se... |
35 36 37 38 39 40 41 |
.capabilities = ( #ifdef CONFIG_MMU /* permit private copies of the data to be taken */ BDI_CAP_MAP_COPY | #endif /* permit direct mmap, for read, write or exec */ BDI_CAP_MAP_DIRECT | |
371d217ee char: Mark /dev/z... |
42 43 44 |
BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP | /* no writeback happens */ BDI_CAP_NO_ACCT_AND_WRITEBACK), |
5da6185bc [PATCH] NOMMU: Se... |
45 |
}; |
1da177e4c Linux-2.6.12-rc2 |
46 |
static struct kobj_map *cdev_map; |
58383af62 [PATCH] kobj_map ... |
47 |
static DEFINE_MUTEX(chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
48 49 50 51 52 53 |
static struct char_device_struct { struct char_device_struct *next; unsigned int major; unsigned int baseminor; int minorct; |
7170be5f5 [PATCH] convert /... |
54 |
char name[64]; |
1da177e4c Linux-2.6.12-rc2 |
55 |
struct cdev *cdev; /* will die */ |
68eef3b47 [PATCH] Simplify ... |
56 |
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE]; |
1da177e4c Linux-2.6.12-rc2 |
57 58 |
/* index in the above */ |
e61eb2e93 fs/block: type si... |
59 |
static inline int major_to_index(unsigned major) |
1da177e4c Linux-2.6.12-rc2 |
60 |
{ |
68eef3b47 [PATCH] Simplify ... |
61 |
return major % CHRDEV_MAJOR_HASH_SIZE; |
7170be5f5 [PATCH] convert /... |
62 |
} |
68eef3b47 [PATCH] Simplify ... |
63 |
#ifdef CONFIG_PROC_FS |
7170be5f5 [PATCH] convert /... |
64 |
|
68eef3b47 [PATCH] Simplify ... |
65 |
void chrdev_show(struct seq_file *f, off_t offset) |
7170be5f5 [PATCH] convert /... |
66 67 |
{ struct char_device_struct *cd; |
7170be5f5 [PATCH] convert /... |
68 |
|
68eef3b47 [PATCH] Simplify ... |
69 70 71 72 73 74 |
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 |
75 |
} |
7170be5f5 [PATCH] convert /... |
76 |
} |
68eef3b47 [PATCH] Simplify ... |
77 |
#endif /* CONFIG_PROC_FS */ |
1da177e4c Linux-2.6.12-rc2 |
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
/* * 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... |
97 |
cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
98 99 |
if (cd == NULL) return ERR_PTR(-ENOMEM); |
58383af62 [PATCH] kobj_map ... |
100 |
mutex_lock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
/* 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; ret = major; } cd->major = major; cd->baseminor = baseminor; cd->minorct = minorct; |
8c4018884 fs: fix name over... |
120 |
strlcpy(cd->name, name, sizeof(cd->name)); |
1da177e4c Linux-2.6.12-rc2 |
121 122 123 124 125 |
i = major_to_index(major); for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) if ((*cp)->major > major || |
01d553d0f [PATCH] Chardev c... |
126 127 128 |
((*cp)->major == major && (((*cp)->baseminor >= baseminor) || ((*cp)->baseminor + (*cp)->minorct > baseminor)))) |
1da177e4c Linux-2.6.12-rc2 |
129 |
break; |
01d553d0f [PATCH] Chardev c... |
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
/* 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 |
149 |
} |
01d553d0f [PATCH] Chardev c... |
150 |
|
1da177e4c Linux-2.6.12-rc2 |
151 152 |
cd->next = *cp; *cp = cd; |
58383af62 [PATCH] kobj_map ... |
153 |
mutex_unlock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
154 155 |
return cd; out: |
58383af62 [PATCH] kobj_map ... |
156 |
mutex_unlock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
157 158 159 160 161 162 163 164 165 |
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 ... |
166 |
mutex_lock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
167 168 169 170 171 172 173 174 175 |
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 ... |
176 |
mutex_unlock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
177 178 |
return cd; } |
cf3e43dbe [PATCH] cdev docu... |
179 180 181 182 183 184 185 186 187 |
/** * 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 |
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
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... |
212 213 214 215 216 217 218 219 220 221 222 |
/** * 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 |
223 224 225 226 227 228 229 230 231 232 |
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... |
233 |
/** |
1905b1bfc chrdev: implement... |
234 |
* __register_chrdev() - create and register a cdev occupying a range of minors |
d247e2c66 [PATCH] add funct... |
235 |
* @major: major device number or 0 for dynamic allocation |
1905b1bfc chrdev: implement... |
236 237 |
* @baseminor: first of the requested range of minor numbers * @count: the number of minor numbers required |
d247e2c66 [PATCH] add funct... |
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
* @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... |
253 |
*/ |
1905b1bfc chrdev: implement... |
254 255 256 |
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 |
257 258 259 |
{ struct char_device_struct *cd; struct cdev *cdev; |
1da177e4c Linux-2.6.12-rc2 |
260 |
int err = -ENOMEM; |
1905b1bfc chrdev: implement... |
261 |
cd = __register_chrdev_region(major, baseminor, count, name); |
1da177e4c Linux-2.6.12-rc2 |
262 263 264 265 266 267 268 269 270 271 |
if (IS_ERR(cd)) return PTR_ERR(cd); cdev = cdev_alloc(); if (!cdev) goto out2; cdev->owner = fops->owner; cdev->ops = fops; kobject_set_name(&cdev->kobj, "%s", name); |
1da177e4c Linux-2.6.12-rc2 |
272 |
|
1905b1bfc chrdev: implement... |
273 |
err = cdev_add(cdev, MKDEV(cd->major, baseminor), count); |
1da177e4c Linux-2.6.12-rc2 |
274 275 276 277 278 279 280 281 282 |
if (err) goto out; cd->cdev = cdev; return major ? 0 : cd->major; out: kobject_put(&cdev->kobj); out2: |
1905b1bfc chrdev: implement... |
283 |
kfree(__unregister_chrdev_region(cd->major, baseminor, count)); |
1da177e4c Linux-2.6.12-rc2 |
284 285 |
return err; } |
cf3e43dbe [PATCH] cdev docu... |
286 287 288 289 290 291 292 293 294 |
/** * 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 |
295 296 297 298 299 300 301 302 303 304 305 306 |
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... |
307 308 309 310 311 312 313 314 315 316 317 318 319 |
/** * __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 |
320 321 |
{ struct char_device_struct *cd; |
1905b1bfc chrdev: implement... |
322 323 |
cd = __unregister_chrdev_region(major, baseminor, count); |
1da177e4c Linux-2.6.12-rc2 |
324 325 326 |
if (cd && cd->cdev) cdev_del(cd->cdev); kfree(cd); |
1da177e4c Linux-2.6.12-rc2 |
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
} 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... |
347 |
struct module *owner = p->owner; |
1da177e4c Linux-2.6.12-rc2 |
348 |
kobject_put(&p->kobj); |
7da6844cf [PATCH] cdev: cde... |
349 |
module_put(owner); |
1da177e4c Linux-2.6.12-rc2 |
350 351 352 353 354 355 |
} } /* * Called every time a character special file is opened */ |
922f9cfa7 fs/char_dev.c: ch... |
356 |
static int chrdev_open(struct inode *inode, struct file *filp) |
1da177e4c Linux-2.6.12-rc2 |
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
{ 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 ... |
373 374 |
/* Check i_cdev again in case somebody beat us to it while we dropped the lock. */ |
1da177e4c Linux-2.6.12-rc2 |
375 376 377 |
p = inode->i_cdev; if (!p) { inode->i_cdev = p = new; |
1da177e4c Linux-2.6.12-rc2 |
378 379 380 381 382 383 384 385 386 387 |
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... |
388 389 |
ret = -ENXIO; |
1da177e4c Linux-2.6.12-rc2 |
390 |
filp->f_op = fops_get(p->ops); |
a518ab932 [PATCH] tidy up c... |
391 392 393 394 |
if (!filp->f_op) goto out_cdev_put; if (filp->f_op->open) { |
1da177e4c Linux-2.6.12-rc2 |
395 |
ret = filp->f_op->open(inode,filp); |
a518ab932 [PATCH] tidy up c... |
396 397 398 399 400 401 402 403 |
if (ret) goto out_cdev_put; } return 0; out_cdev_put: cdev_put(p); |
1da177e4c Linux-2.6.12-rc2 |
404 405 406 407 408 409 410 411 412 413 |
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... |
414 |
static void cdev_purge(struct cdev *cdev) |
1da177e4c Linux-2.6.12-rc2 |
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 |
{ 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... |
431 |
const struct file_operations def_chr_fops = { |
1da177e4c Linux-2.6.12-rc2 |
432 |
.open = chrdev_open, |
6038f373a llseek: automatic... |
433 |
.llseek = noop_llseek, |
1da177e4c Linux-2.6.12-rc2 |
434 435 436 437 438 439 440 441 442 443 444 445 446 |
}; 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... |
447 448 449 450 451 452 453 454 455 456 |
/** * 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 |
457 458 459 460 461 462 463 464 465 466 467 |
int cdev_add(struct cdev *p, dev_t dev, unsigned count) { p->dev = dev; p->count = count; return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p); } static void cdev_unmap(dev_t dev, unsigned count) { kobj_unmap(cdev_map, dev, count); } |
cf3e43dbe [PATCH] cdev docu... |
468 469 470 471 472 473 474 |
/** * 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 |
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
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); cdev_purge(p); } static void cdev_dynamic_release(struct kobject *kobj) { struct cdev *p = container_of(kobj, struct cdev, kobj); cdev_purge(p); kfree(p); } 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... |
502 503 504 505 506 |
/** * cdev_alloc() - allocate a cdev structure * * Allocates and returns a cdev structure, or NULL on failure. */ |
1da177e4c Linux-2.6.12-rc2 |
507 508 |
struct cdev *cdev_alloc(void) { |
11b0b5abb [PATCH] use kzall... |
509 |
struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
510 |
if (p) { |
1da177e4c Linux-2.6.12-rc2 |
511 |
INIT_LIST_HEAD(&p->list); |
f9cb074bf Kobject: rename k... |
512 |
kobject_init(&p->kobj, &ktype_cdev_dynamic); |
1da177e4c Linux-2.6.12-rc2 |
513 514 515 |
} return p; } |
cf3e43dbe [PATCH] cdev docu... |
516 517 518 519 520 521 522 523 |
/** * 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... |
524 |
void cdev_init(struct cdev *cdev, const struct file_operations *fops) |
1da177e4c Linux-2.6.12-rc2 |
525 526 527 |
{ memset(cdev, 0, sizeof *cdev); INIT_LIST_HEAD(&cdev->list); |
f9cb074bf Kobject: rename k... |
528 |
kobject_init(&cdev->kobj, &ktype_cdev_default); |
1da177e4c Linux-2.6.12-rc2 |
529 530 531 532 533 534 535 536 537 538 539 540 541 542 |
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); |
e0bf68dde mm: bdi init hooks |
543 |
bdi_init(&directly_mappable_cdev_bdi); |
1da177e4c Linux-2.6.12-rc2 |
544 545 546 547 548 549 550 551 552 553 554 |
} /* 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... |
555 556 |
EXPORT_SYMBOL(__register_chrdev); EXPORT_SYMBOL(__unregister_chrdev); |
5da6185bc [PATCH] NOMMU: Se... |
557 |
EXPORT_SYMBOL(directly_mappable_cdev_bdi); |