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