Blame view

fs/char_dev.c 16.7 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
   *  linux/fs/char_dev.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
  #include <linux/init.h>
  #include <linux/fs.h>
b446b60e4   Andrew Morton   [PATCH] rework re...
9
  #include <linux/kdev_t.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
  #include <linux/slab.h>
  #include <linux/string.h>
  
  #include <linux/major.h>
  #include <linux/errno.h>
  #include <linux/module.h>
68eef3b47   Joe Korty   [PATCH] Simplify ...
16
  #include <linux/seq_file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
  
  #include <linux/kobject.h>
  #include <linux/kobj_map.h>
  #include <linux/cdev.h>
58383af62   Jes Sorensen   [PATCH] kobj_map ...
21
  #include <linux/mutex.h>
5da6185bc   David Howells   [PATCH] NOMMU: Se...
22
  #include <linux/backing-dev.h>
31d1d48e1   David Howells   Fix init ordering...
23
  #include <linux/tty.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24

07f3f05c1   David Howells   [PATCH] BLOCK: Mo...
25
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
  
  static struct kobj_map *cdev_map;
58383af62   Jes Sorensen   [PATCH] kobj_map ...
28
  static DEFINE_MUTEX(chrdevs_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

8a932f73e   Logan Gunthorpe   char_dev: order /...
30
  #define CHRDEV_MAJOR_HASH_SIZE 255
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
  static struct char_device_struct {
  	struct char_device_struct *next;
  	unsigned int major;
  	unsigned int baseminor;
  	int minorct;
7170be5f5   Neil Horman   [PATCH] convert /...
36
  	char name[64];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  	struct cdev *cdev;		/* will die */
68eef3b47   Joe Korty   [PATCH] Simplify ...
38
  } *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  
  /* index in the above */
e61eb2e93   Yang Zhang   fs/block: type si...
41
  static inline int major_to_index(unsigned major)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  {
68eef3b47   Joe Korty   [PATCH] Simplify ...
43
  	return major % CHRDEV_MAJOR_HASH_SIZE;
7170be5f5   Neil Horman   [PATCH] convert /...
44
  }
68eef3b47   Joe Korty   [PATCH] Simplify ...
45
  #ifdef CONFIG_PROC_FS
7170be5f5   Neil Horman   [PATCH] convert /...
46

68eef3b47   Joe Korty   [PATCH] Simplify ...
47
  void chrdev_show(struct seq_file *f, off_t offset)
7170be5f5   Neil Horman   [PATCH] convert /...
48
49
  {
  	struct char_device_struct *cd;
7170be5f5   Neil Horman   [PATCH] convert /...
50

8a932f73e   Logan Gunthorpe   char_dev: order /...
51
52
53
  	mutex_lock(&chrdevs_lock);
  	for (cd = chrdevs[major_to_index(offset)]; cd; cd = cd->next) {
  		if (cd->major == offset)
68eef3b47   Joe Korty   [PATCH] Simplify ...
54
55
  			seq_printf(f, "%3d %s
  ", cd->major, cd->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  	}
8a932f73e   Logan Gunthorpe   char_dev: order /...
57
  	mutex_unlock(&chrdevs_lock);
7170be5f5   Neil Horman   [PATCH] convert /...
58
  }
68eef3b47   Joe Korty   [PATCH] Simplify ...
59
  #endif /* CONFIG_PROC_FS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

a5d31a3f8   Logan Gunthorpe   char_dev: extend ...
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  static int find_dynamic_major(void)
  {
  	int i;
  	struct char_device_struct *cd;
  
  	for (i = ARRAY_SIZE(chrdevs)-1; i > CHRDEV_MAJOR_DYN_END; i--) {
  		if (chrdevs[i] == NULL)
  			return i;
  	}
  
  	for (i = CHRDEV_MAJOR_DYN_EXT_START;
  	     i > CHRDEV_MAJOR_DYN_EXT_END; i--) {
  		for (cd = chrdevs[major_to_index(i)]; cd; cd = cd->next)
  			if (cd->major == i)
  				break;
  
  		if (cd == NULL || cd->major != i)
  			return i;
  	}
  
  	return -EBUSY;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  /*
   * 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   Oliver Neukum   [PATCH] use kzall...
101
  	cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
  	if (cd == NULL)
  		return ERR_PTR(-ENOMEM);
58383af62   Jes Sorensen   [PATCH] kobj_map ...
104
  	mutex_lock(&chrdevs_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  	if (major == 0) {
a5d31a3f8   Logan Gunthorpe   char_dev: extend ...
107
108
109
110
111
  		ret = find_dynamic_major();
  		if (ret < 0) {
  			pr_err("CHRDEV \"%s\" dynamic allocation region is full
  ",
  			       name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
  			goto out;
  		}
a5d31a3f8   Logan Gunthorpe   char_dev: extend ...
114
  		major = ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  	}
8a932f73e   Logan Gunthorpe   char_dev: order /...
116
117
118
119
120
121
122
  	if (major >= CHRDEV_MAJOR_MAX) {
  		pr_err("CHRDEV \"%s\" major requested (%d) is greater than the maximum (%d)
  ",
  		       name, major, CHRDEV_MAJOR_MAX);
  		ret = -EINVAL;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
  	cd->major = major;
  	cd->baseminor = baseminor;
  	cd->minorct = minorct;
8c4018884   Cyrill Gorcunov   fs: fix name over...
126
  	strlcpy(cd->name, name, sizeof(cd->name));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
  
  	i = major_to_index(major);
  
  	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
  		if ((*cp)->major > major ||
01d553d0f   Amos Waterland   [PATCH] Chardev c...
132
133
134
  		    ((*cp)->major == major &&
  		     (((*cp)->baseminor >= baseminor) ||
  		      ((*cp)->baseminor + (*cp)->minorct > baseminor))))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
  			break;
01d553d0f   Amos Waterland   [PATCH] Chardev c...
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  
  	/* 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   Linus Torvalds   Linux-2.6.12-rc2
155
  	}
01d553d0f   Amos Waterland   [PATCH] Chardev c...
156

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
  	cd->next = *cp;
  	*cp = cd;
58383af62   Jes Sorensen   [PATCH] kobj_map ...
159
  	mutex_unlock(&chrdevs_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
  	return cd;
  out:
58383af62   Jes Sorensen   [PATCH] kobj_map ...
162
  	mutex_unlock(&chrdevs_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
167
168
169
170
171
  	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   Jes Sorensen   [PATCH] kobj_map ...
172
  	mutex_lock(&chrdevs_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
176
177
178
179
180
181
  	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   Jes Sorensen   [PATCH] kobj_map ...
182
  	mutex_unlock(&chrdevs_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
  	return cd;
  }
cf3e43dbe   Jonathan Corbet   [PATCH] cdev docu...
185
186
187
188
189
190
191
192
193
  /**
   * 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   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
  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   Jonathan Corbet   [PATCH] cdev docu...
218
219
220
221
222
223
224
225
226
227
228
  /**
   * 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   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
235
236
237
238
  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   Rolf Eike Beer   [PATCH] add funct...
239
  /**
1905b1bfc   Tejun Heo   chrdev: implement...
240
   * __register_chrdev() - create and register a cdev occupying a range of minors
d247e2c66   Rolf Eike Beer   [PATCH] add funct...
241
   * @major: major device number or 0 for dynamic allocation
1905b1bfc   Tejun Heo   chrdev: implement...
242
243
   * @baseminor: first of the requested range of minor numbers
   * @count: the number of minor numbers required
d247e2c66   Rolf Eike Beer   [PATCH] add funct...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
   * @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   Rolf Eike Beer   [PATCH] add funct...
259
   */
1905b1bfc   Tejun Heo   chrdev: implement...
260
261
262
  int __register_chrdev(unsigned int major, unsigned int baseminor,
  		      unsigned int count, const char *name,
  		      const struct file_operations *fops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
  {
  	struct char_device_struct *cd;
  	struct cdev *cdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  	int err = -ENOMEM;
1905b1bfc   Tejun Heo   chrdev: implement...
267
  	cd = __register_chrdev_region(major, baseminor, count, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
  	if (IS_ERR(cd))
  		return PTR_ERR(cd);
1ff97647f   Greg Kroah-Hartman   char_dev.c: fix u...
270

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
276
277
  	cdev = cdev_alloc();
  	if (!cdev)
  		goto out2;
  
  	cdev->owner = fops->owner;
  	cdev->ops = fops;
  	kobject_set_name(&cdev->kobj, "%s", name);
1ff97647f   Greg Kroah-Hartman   char_dev.c: fix u...
278

1905b1bfc   Tejun Heo   chrdev: implement...
279
  	err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
284
285
286
287
288
  	if (err)
  		goto out;
  
  	cd->cdev = cdev;
  
  	return major ? 0 : cd->major;
  out:
  	kobject_put(&cdev->kobj);
  out2:
1905b1bfc   Tejun Heo   chrdev: implement...
289
  	kfree(__unregister_chrdev_region(cd->major, baseminor, count));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
  	return err;
  }
cf3e43dbe   Jonathan Corbet   [PATCH] cdev docu...
292
  /**
594069bc3   Partha Pratim Mukherjee   fs/char_dev.c: fi...
293
   * unregister_chrdev_region() - unregister a range of device numbers
cf3e43dbe   Jonathan Corbet   [PATCH] cdev docu...
294
295
296
297
298
299
300
   * @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   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
305
306
307
308
309
310
311
312
  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   Tejun Heo   chrdev: implement...
313
314
315
316
317
318
319
320
321
322
323
324
325
  /**
   * __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   Linus Torvalds   Linux-2.6.12-rc2
326
327
  {
  	struct char_device_struct *cd;
1905b1bfc   Tejun Heo   chrdev: implement...
328
329
  
  	cd = __unregister_chrdev_region(major, baseminor, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
  	if (cd && cd->cdev)
  		cdev_del(cd->cdev);
  	kfree(cd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
  }
  
  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   Brian King   [PATCH] cdev: cde...
353
  		struct module *owner = p->owner;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  		kobject_put(&p->kobj);
7da6844cf   Brian King   [PATCH] cdev: cde...
355
  		module_put(owner);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
358
359
360
361
  	}
  }
  
  /*
   * Called every time a character special file is opened
   */
922f9cfa7   Denis Cheng   fs/char_dev.c: ch...
362
  static int chrdev_open(struct inode *inode, struct file *filp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
  {
e84f9e57b   Al Viro   consolidate the r...
364
  	const struct file_operations *fops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
  	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   Jonathan Corbet   Add a comment in ...
380
381
  		/* Check i_cdev again in case somebody beat us to it while
  		   we dropped the lock. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
383
384
  		p = inode->i_cdev;
  		if (!p) {
  			inode->i_cdev = p = new;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
388
389
390
391
392
393
394
  			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   Christoph Hellwig   [PATCH] tidy up c...
395
396
  
  	ret = -ENXIO;
e84f9e57b   Al Viro   consolidate the r...
397
398
  	fops = fops_get(p->ops);
  	if (!fops)
a518ab932   Christoph Hellwig   [PATCH] tidy up c...
399
  		goto out_cdev_put;
e84f9e57b   Al Viro   consolidate the r...
400
  	replace_fops(filp, fops);
a518ab932   Christoph Hellwig   [PATCH] tidy up c...
401
  	if (filp->f_op->open) {
1ff97647f   Greg Kroah-Hartman   char_dev.c: fix u...
402
  		ret = filp->f_op->open(inode, filp);
a518ab932   Christoph Hellwig   [PATCH] tidy up c...
403
404
405
406
407
408
409
410
  		if (ret)
  			goto out_cdev_put;
  	}
  
  	return 0;
  
   out_cdev_put:
  	cdev_put(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
416
417
418
  	return ret;
  }
  
  void cd_forget(struct inode *inode)
  {
  	spin_lock(&cdev_lock);
  	list_del_init(&inode->i_devices);
  	inode->i_cdev = NULL;
3bc52c45b   Dan Williams   dax: define a uni...
419
  	inode->i_mapping = &inode->i_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
  	spin_unlock(&cdev_lock);
  }
75c96f858   Adrian Bunk   [PATCH] make some...
422
  static void cdev_purge(struct cdev *cdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  {
  	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   Arjan van de Ven   [PATCH] Make most...
439
  const struct file_operations def_chr_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  	.open = chrdev_open,
6038f373a   Arnd Bergmann   llseek: automatic...
441
  	.llseek = noop_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
446
447
448
449
450
451
452
453
454
  };
  
  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   Jonathan Corbet   [PATCH] cdev docu...
455
456
457
458
459
460
461
462
463
464
  /**
   * 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   Linus Torvalds   Linux-2.6.12-rc2
465
466
  int cdev_add(struct cdev *p, dev_t dev, unsigned count)
  {
2f0157f13   Dmitry Torokhov   char_dev: pin par...
467
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
  	p->dev = dev;
  	p->count = count;
2f0157f13   Dmitry Torokhov   char_dev: pin par...
470
471
472
473
474
475
476
477
478
  
  	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   Linus Torvalds   Linux-2.6.12-rc2
479
  }
233ed09d7   Logan Gunthorpe   chardev: add help...
480
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
508
509
510
511
512
513
514
515
516
517
518
519
520
521
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
547
548
549
550
551
552
553
554
555
556
557
  /**
   * cdev_set_parent() - set the parent kobject for a char device
   * @p: the cdev structure
   * @kobj: the kobject to take a reference to
   *
   * cdev_set_parent() sets a parent kobject which will be referenced
   * appropriately so the parent is not freed before the cdev. This
   * should be called before cdev_add.
   */
  void cdev_set_parent(struct cdev *p, struct kobject *kobj)
  {
  	WARN_ON(!kobj->state_initialized);
  	p->kobj.parent = kobj;
  }
  
  /**
   * cdev_device_add() - add a char device and it's corresponding
   *	struct device, linkink
   * @dev: the device structure
   * @cdev: the cdev structure
   *
   * cdev_device_add() adds the char device represented by @cdev to the system,
   * just as cdev_add does. It then adds @dev to the system using device_add
   * The dev_t for the char device will be taken from the struct device which
   * needs to be initialized first. This helper function correctly takes a
   * reference to the parent device so the parent will not get released until
   * all references to the cdev are released.
   *
   * This helper uses dev->devt for the device number. If it is not set
   * it will not add the cdev and it will be equivalent to device_add.
   *
   * This function should be used whenever the struct cdev and the
   * struct device are members of the same structure whose lifetime is
   * managed by the struct device.
   *
   * NOTE: Callers must assume that userspace was able to open the cdev and
   * can call cdev fops callbacks at any time, even if this function fails.
   */
  int cdev_device_add(struct cdev *cdev, struct device *dev)
  {
  	int rc = 0;
  
  	if (dev->devt) {
  		cdev_set_parent(cdev, &dev->kobj);
  
  		rc = cdev_add(cdev, dev->devt, 1);
  		if (rc)
  			return rc;
  	}
  
  	rc = device_add(dev);
  	if (rc)
  		cdev_del(cdev);
  
  	return rc;
  }
  
  /**
   * cdev_device_del() - inverse of cdev_device_add
   * @dev: the device structure
   * @cdev: the cdev structure
   *
   * cdev_device_del() is a helper function to call cdev_del and device_del.
   * It should be used whenever cdev_device_add is used.
   *
   * If dev->devt is not set it will not remove the cdev and will be equivalent
   * to device_del.
   *
   * NOTE: This guarantees that associated sysfs callbacks are not running
   * or runnable, however any cdevs already open will remain and their fops
   * will still be callable even after this function returns.
   */
  void cdev_device_del(struct cdev *cdev, struct device *dev)
  {
  	device_del(dev);
  	if (dev->devt)
  		cdev_del(cdev);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
560
561
  static void cdev_unmap(dev_t dev, unsigned count)
  {
  	kobj_unmap(cdev_map, dev, count);
  }
cf3e43dbe   Jonathan Corbet   [PATCH] cdev docu...
562
563
564
565
566
567
  /**
   * 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.
233ed09d7   Logan Gunthorpe   chardev: add help...
568
569
570
571
   *
   * NOTE: This guarantees that cdev device will no longer be able to be
   * opened, however any cdevs already open will remain and their fops will
   * still be callable even after cdev_del returns.
cf3e43dbe   Jonathan Corbet   [PATCH] cdev docu...
572
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
574
575
576
577
578
579
580
581
582
  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   Dmitry Torokhov   char_dev: pin par...
583
  	struct kobject *parent = kobj->parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
  	cdev_purge(p);
2f0157f13   Dmitry Torokhov   char_dev: pin par...
585
  	kobject_put(parent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
588
589
590
  }
  
  static void cdev_dynamic_release(struct kobject *kobj)
  {
  	struct cdev *p = container_of(kobj, struct cdev, kobj);
2f0157f13   Dmitry Torokhov   char_dev: pin par...
591
  	struct kobject *parent = kobj->parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
  	cdev_purge(p);
  	kfree(p);
2f0157f13   Dmitry Torokhov   char_dev: pin par...
594
  	kobject_put(parent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
597
598
599
600
601
602
603
  }
  
  static struct kobj_type ktype_cdev_default = {
  	.release	= cdev_default_release,
  };
  
  static struct kobj_type ktype_cdev_dynamic = {
  	.release	= cdev_dynamic_release,
  };
cf3e43dbe   Jonathan Corbet   [PATCH] cdev docu...
604
605
606
607
608
  /**
   * cdev_alloc() - allocate a cdev structure
   *
   * Allocates and returns a cdev structure, or NULL on failure.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
  struct cdev *cdev_alloc(void)
  {
11b0b5abb   Oliver Neukum   [PATCH] use kzall...
611
  	struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
  	if (p) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
  		INIT_LIST_HEAD(&p->list);
f9cb074bf   Greg Kroah-Hartman   Kobject: rename k...
614
  		kobject_init(&p->kobj, &ktype_cdev_dynamic);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
617
  	}
  	return p;
  }
cf3e43dbe   Jonathan Corbet   [PATCH] cdev docu...
618
619
620
621
622
623
624
625
  /**
   * 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   Arjan van de Ven   [PATCH] mark f_op...
626
  void cdev_init(struct cdev *cdev, const struct file_operations *fops)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
  {
  	memset(cdev, 0, sizeof *cdev);
  	INIT_LIST_HEAD(&cdev->list);
f9cb074bf   Greg Kroah-Hartman   Kobject: rename k...
630
  	kobject_init(&cdev->kobj, &ktype_cdev_default);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
  	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);
233ed09d7   Logan Gunthorpe   chardev: add help...
656
657
658
  EXPORT_SYMBOL(cdev_set_parent);
  EXPORT_SYMBOL(cdev_device_add);
  EXPORT_SYMBOL(cdev_device_del);
1905b1bfc   Tejun Heo   chrdev: implement...
659
660
  EXPORT_SYMBOL(__register_chrdev);
  EXPORT_SYMBOL(__unregister_chrdev);