Blame view
fs/char_dev.c
13.5 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 |
/* temporary */ if (major == 0) { for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) { if (chrdevs[i] == NULL) break; } |
49db08c35 chrdev: emit a wa... |
88 |
if (i < CHRDEV_MAJOR_DYN_END) |
077e2642f chardev: add miss... |
89 90 |
pr_warn("CHRDEV \"%s\" major number %d goes below the dynamic allocation range ", |
49db08c35 chrdev: emit a wa... |
91 |
name, i); |
1da177e4c Linux-2.6.12-rc2 |
92 93 94 95 96 |
if (i == 0) { ret = -EBUSY; goto out; } major = i; |
1da177e4c Linux-2.6.12-rc2 |
97 98 99 100 101 |
} cd->major = major; cd->baseminor = baseminor; cd->minorct = minorct; |
8c4018884 fs: fix name over... |
102 |
strlcpy(cd->name, name, sizeof(cd->name)); |
1da177e4c Linux-2.6.12-rc2 |
103 104 105 106 107 |
i = major_to_index(major); for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) if ((*cp)->major > major || |
01d553d0f [PATCH] Chardev c... |
108 109 110 |
((*cp)->major == major && (((*cp)->baseminor >= baseminor) || ((*cp)->baseminor + (*cp)->minorct > baseminor)))) |
1da177e4c Linux-2.6.12-rc2 |
111 |
break; |
01d553d0f [PATCH] Chardev c... |
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
/* 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 |
131 |
} |
01d553d0f [PATCH] Chardev c... |
132 |
|
1da177e4c Linux-2.6.12-rc2 |
133 134 |
cd->next = *cp; *cp = cd; |
58383af62 [PATCH] kobj_map ... |
135 |
mutex_unlock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
136 137 |
return cd; out: |
58383af62 [PATCH] kobj_map ... |
138 |
mutex_unlock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
139 140 141 142 143 144 145 146 147 |
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 ... |
148 |
mutex_lock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
149 150 151 152 153 154 155 156 157 |
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 ... |
158 |
mutex_unlock(&chrdevs_lock); |
1da177e4c Linux-2.6.12-rc2 |
159 160 |
return cd; } |
cf3e43dbe [PATCH] cdev docu... |
161 162 163 164 165 166 167 168 169 |
/** * 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 |
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
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... |
194 195 196 197 198 199 200 201 202 203 204 |
/** * 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 |
205 206 207 208 209 210 211 212 213 214 |
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... |
215 |
/** |
1905b1bfc chrdev: implement... |
216 |
* __register_chrdev() - create and register a cdev occupying a range of minors |
d247e2c66 [PATCH] add funct... |
217 |
* @major: major device number or 0 for dynamic allocation |
1905b1bfc chrdev: implement... |
218 219 |
* @baseminor: first of the requested range of minor numbers * @count: the number of minor numbers required |
d247e2c66 [PATCH] add funct... |
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
* @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... |
235 |
*/ |
1905b1bfc chrdev: implement... |
236 237 238 |
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 |
239 240 241 |
{ struct char_device_struct *cd; struct cdev *cdev; |
1da177e4c Linux-2.6.12-rc2 |
242 |
int err = -ENOMEM; |
1905b1bfc chrdev: implement... |
243 |
cd = __register_chrdev_region(major, baseminor, count, name); |
1da177e4c Linux-2.6.12-rc2 |
244 245 |
if (IS_ERR(cd)) return PTR_ERR(cd); |
1ff97647f char_dev.c: fix u... |
246 |
|
1da177e4c Linux-2.6.12-rc2 |
247 248 249 250 251 252 253 |
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... |
254 |
|
1905b1bfc chrdev: implement... |
255 |
err = cdev_add(cdev, MKDEV(cd->major, baseminor), count); |
1da177e4c Linux-2.6.12-rc2 |
256 257 258 259 260 261 262 263 264 |
if (err) goto out; cd->cdev = cdev; return major ? 0 : cd->major; out: kobject_put(&cdev->kobj); out2: |
1905b1bfc chrdev: implement... |
265 |
kfree(__unregister_chrdev_region(cd->major, baseminor, count)); |
1da177e4c Linux-2.6.12-rc2 |
266 267 |
return err; } |
cf3e43dbe [PATCH] cdev docu... |
268 |
/** |
594069bc3 fs/char_dev.c: fi... |
269 |
* unregister_chrdev_region() - unregister a range of device numbers |
cf3e43dbe [PATCH] cdev docu... |
270 271 272 273 274 275 276 |
* @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 |
277 278 279 280 281 282 283 284 285 286 287 288 |
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... |
289 290 291 292 293 294 295 296 297 298 299 300 301 |
/** * __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 |
302 303 |
{ struct char_device_struct *cd; |
1905b1bfc chrdev: implement... |
304 305 |
cd = __unregister_chrdev_region(major, baseminor, count); |
1da177e4c Linux-2.6.12-rc2 |
306 307 308 |
if (cd && cd->cdev) cdev_del(cd->cdev); kfree(cd); |
1da177e4c Linux-2.6.12-rc2 |
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
} 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... |
329 |
struct module *owner = p->owner; |
1da177e4c Linux-2.6.12-rc2 |
330 |
kobject_put(&p->kobj); |
7da6844cf [PATCH] cdev: cde... |
331 |
module_put(owner); |
1da177e4c Linux-2.6.12-rc2 |
332 333 334 335 336 337 |
} } /* * Called every time a character special file is opened */ |
922f9cfa7 fs/char_dev.c: ch... |
338 |
static int chrdev_open(struct inode *inode, struct file *filp) |
1da177e4c Linux-2.6.12-rc2 |
339 |
{ |
e84f9e57b consolidate the r... |
340 |
const struct file_operations *fops; |
1da177e4c Linux-2.6.12-rc2 |
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
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 ... |
356 357 |
/* Check i_cdev again in case somebody beat us to it while we dropped the lock. */ |
1da177e4c Linux-2.6.12-rc2 |
358 359 360 |
p = inode->i_cdev; if (!p) { inode->i_cdev = p = new; |
1da177e4c Linux-2.6.12-rc2 |
361 362 363 364 365 366 367 368 369 370 |
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... |
371 372 |
ret = -ENXIO; |
e84f9e57b consolidate the r... |
373 374 |
fops = fops_get(p->ops); if (!fops) |
a518ab932 [PATCH] tidy up c... |
375 |
goto out_cdev_put; |
e84f9e57b consolidate the r... |
376 |
replace_fops(filp, fops); |
a518ab932 [PATCH] tidy up c... |
377 |
if (filp->f_op->open) { |
1ff97647f char_dev.c: fix u... |
378 |
ret = filp->f_op->open(inode, filp); |
a518ab932 [PATCH] tidy up c... |
379 380 381 382 383 384 385 386 |
if (ret) goto out_cdev_put; } return 0; out_cdev_put: cdev_put(p); |
1da177e4c Linux-2.6.12-rc2 |
387 388 389 390 391 392 393 394 |
return ret; } void cd_forget(struct inode *inode) { spin_lock(&cdev_lock); list_del_init(&inode->i_devices); inode->i_cdev = NULL; |
3bc52c45b dax: define a uni... |
395 |
inode->i_mapping = &inode->i_data; |
1da177e4c Linux-2.6.12-rc2 |
396 397 |
spin_unlock(&cdev_lock); } |
75c96f858 [PATCH] make some... |
398 |
static void cdev_purge(struct cdev *cdev) |
1da177e4c Linux-2.6.12-rc2 |
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
{ 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... |
415 |
const struct file_operations def_chr_fops = { |
1da177e4c Linux-2.6.12-rc2 |
416 |
.open = chrdev_open, |
6038f373a llseek: automatic... |
417 |
.llseek = noop_llseek, |
1da177e4c Linux-2.6.12-rc2 |
418 419 420 421 422 423 424 425 426 427 428 429 430 |
}; 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... |
431 432 433 434 435 436 437 438 439 440 |
/** * 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 |
441 442 |
int cdev_add(struct cdev *p, dev_t dev, unsigned count) { |
2f0157f13 char_dev: pin par... |
443 |
int error; |
1da177e4c Linux-2.6.12-rc2 |
444 445 |
p->dev = dev; p->count = count; |
2f0157f13 char_dev: pin par... |
446 447 448 449 450 451 452 453 454 |
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 |
455 456 457 458 459 460 |
} static void cdev_unmap(dev_t dev, unsigned count) { kobj_unmap(cdev_map, dev, count); } |
cf3e43dbe [PATCH] cdev docu... |
461 462 463 464 465 466 467 |
/** * 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 |
468 469 470 471 472 473 474 475 476 477 |
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... |
478 |
struct kobject *parent = kobj->parent; |
1da177e4c Linux-2.6.12-rc2 |
479 |
cdev_purge(p); |
2f0157f13 char_dev: pin par... |
480 |
kobject_put(parent); |
1da177e4c Linux-2.6.12-rc2 |
481 482 483 484 485 |
} static void cdev_dynamic_release(struct kobject *kobj) { struct cdev *p = container_of(kobj, struct cdev, kobj); |
2f0157f13 char_dev: pin par... |
486 |
struct kobject *parent = kobj->parent; |
1da177e4c Linux-2.6.12-rc2 |
487 488 |
cdev_purge(p); kfree(p); |
2f0157f13 char_dev: pin par... |
489 |
kobject_put(parent); |
1da177e4c Linux-2.6.12-rc2 |
490 491 492 493 494 495 496 497 498 |
} 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... |
499 500 501 502 503 |
/** * cdev_alloc() - allocate a cdev structure * * Allocates and returns a cdev structure, or NULL on failure. */ |
1da177e4c Linux-2.6.12-rc2 |
504 505 |
struct cdev *cdev_alloc(void) { |
11b0b5abb [PATCH] use kzall... |
506 |
struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
507 |
if (p) { |
1da177e4c Linux-2.6.12-rc2 |
508 |
INIT_LIST_HEAD(&p->list); |
f9cb074bf Kobject: rename k... |
509 |
kobject_init(&p->kobj, &ktype_cdev_dynamic); |
1da177e4c Linux-2.6.12-rc2 |
510 511 512 |
} return p; } |
cf3e43dbe [PATCH] cdev docu... |
513 514 515 516 517 518 519 520 |
/** * 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... |
521 |
void cdev_init(struct cdev *cdev, const struct file_operations *fops) |
1da177e4c Linux-2.6.12-rc2 |
522 523 524 |
{ memset(cdev, 0, sizeof *cdev); INIT_LIST_HEAD(&cdev->list); |
f9cb074bf Kobject: rename k... |
525 |
kobject_init(&cdev->kobj, &ktype_cdev_default); |
1da177e4c Linux-2.6.12-rc2 |
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 |
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... |
551 552 |
EXPORT_SYMBOL(__register_chrdev); EXPORT_SYMBOL(__unregister_chrdev); |