1 b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2 1da177e4SLinus Torvalds /*
3 1da177e4SLinus Torvalds * linux/fs/char_dev.c
4 1da177e4SLinus Torvalds *
5 1da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds
6 1da177e4SLinus Torvalds */
7 1da177e4SLinus Torvalds
8 1da177e4SLinus Torvalds #include <linux/init.h>
9 1da177e4SLinus Torvalds #include <linux/fs.h>
10 b446b60eSAndrew Morton #include <linux/kdev_t.h>
11 1da177e4SLinus Torvalds #include <linux/slab.h>
12 1da177e4SLinus Torvalds #include <linux/string.h>
13 1da177e4SLinus Torvalds
14 1da177e4SLinus Torvalds #include <linux/major.h>
15 1da177e4SLinus Torvalds #include <linux/errno.h>
16 1da177e4SLinus Torvalds #include <linux/module.h>
17 68eef3b4SJoe Korty #include <linux/seq_file.h>
18 1da177e4SLinus Torvalds
19 1da177e4SLinus Torvalds #include <linux/kobject.h>
20 1da177e4SLinus Torvalds #include <linux/kobj_map.h>
21 1da177e4SLinus Torvalds #include <linux/cdev.h>
22 58383af6SJes Sorensen #include <linux/mutex.h>
23 5da6185bSDavid Howells #include <linux/backing-dev.h>
24 31d1d48eSDavid Howells #include <linux/tty.h>
25 1da177e4SLinus Torvalds
26 07f3f05cSDavid Howells #include "internal.h"
27 1da177e4SLinus Torvalds
28 1da177e4SLinus Torvalds static struct kobj_map *cdev_map;
29 1da177e4SLinus Torvalds
30 58383af6SJes Sorensen static DEFINE_MUTEX(chrdevs_lock);
31 1da177e4SLinus Torvalds
32 8a932f73SLogan Gunthorpe #define CHRDEV_MAJOR_HASH_SIZE 255
33 8a932f73SLogan Gunthorpe
34 1da177e4SLinus Torvalds static struct char_device_struct {
35 1da177e4SLinus Torvalds struct char_device_struct *next;
36 1da177e4SLinus Torvalds unsigned int major;
37 1da177e4SLinus Torvalds unsigned int baseminor;
38 1da177e4SLinus Torvalds int minorct;
39 7170be5fSNeil Horman char name[64];
40 1da177e4SLinus Torvalds struct cdev *cdev; /* will die */
41 68eef3b4SJoe Korty } *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
42 1da177e4SLinus Torvalds
43 1da177e4SLinus Torvalds /* index in the above */
major_to_index(unsigned major)44 e61eb2e9SYang Zhang static inline int major_to_index(unsigned major)
45 1da177e4SLinus Torvalds {
46 68eef3b4SJoe Korty return major % CHRDEV_MAJOR_HASH_SIZE;
47 1da177e4SLinus Torvalds }
48 1da177e4SLinus Torvalds
49 68eef3b4SJoe Korty #ifdef CONFIG_PROC_FS
50 68eef3b4SJoe Korty
chrdev_show(struct seq_file * f,off_t offset)51 68eef3b4SJoe Korty void chrdev_show(struct seq_file *f, off_t offset)
52 68eef3b4SJoe Korty {
53 7170be5fSNeil Horman struct char_device_struct *cd;
54 7170be5fSNeil Horman
55 58383af6SJes Sorensen mutex_lock(&chrdevs_lock);
56 8a932f73SLogan Gunthorpe for (cd = chrdevs[major_to_index(offset)]; cd; cd = cd->next) {
57 8a932f73SLogan Gunthorpe if (cd->major == offset)
58 68eef3b4SJoe Korty seq_printf(f, "%3d %s\n", cd->major, cd->name);
59 68eef3b4SJoe Korty }
60 8a932f73SLogan Gunthorpe mutex_unlock(&chrdevs_lock);
61 7170be5fSNeil Horman }
62 7170be5fSNeil Horman
63 68eef3b4SJoe Korty #endif /* CONFIG_PROC_FS */
64 1da177e4SLinus Torvalds
find_dynamic_major(void)65 a5d31a3fSLogan Gunthorpe static int find_dynamic_major(void)
66 a5d31a3fSLogan Gunthorpe {
67 a5d31a3fSLogan Gunthorpe int i;
68 a5d31a3fSLogan Gunthorpe struct char_device_struct *cd;
69 a5d31a3fSLogan Gunthorpe
70 652d703bSSrivatsa S. Bhat for (i = ARRAY_SIZE(chrdevs)-1; i >= CHRDEV_MAJOR_DYN_END; i--) {
71 a5d31a3fSLogan Gunthorpe if (chrdevs[i] == NULL)
72 a5d31a3fSLogan Gunthorpe return i;
73 a5d31a3fSLogan Gunthorpe }
74 a5d31a3fSLogan Gunthorpe
75 a5d31a3fSLogan Gunthorpe for (i = CHRDEV_MAJOR_DYN_EXT_START;
76 652d703bSSrivatsa S. Bhat i >= CHRDEV_MAJOR_DYN_EXT_END; i--) {
77 a5d31a3fSLogan Gunthorpe for (cd = chrdevs[major_to_index(i)]; cd; cd = cd->next)
78 a5d31a3fSLogan Gunthorpe if (cd->major == i)
79 a5d31a3fSLogan Gunthorpe break;
80 a5d31a3fSLogan Gunthorpe
81 652d703bSSrivatsa S. Bhat if (cd == NULL)
82 a5d31a3fSLogan Gunthorpe return i;
83 a5d31a3fSLogan Gunthorpe }
84 a5d31a3fSLogan Gunthorpe
85 a5d31a3fSLogan Gunthorpe return -EBUSY;
86 a5d31a3fSLogan Gunthorpe }
87 a5d31a3fSLogan Gunthorpe
88 1da177e4SLinus Torvalds /*
89 1da177e4SLinus Torvalds * Register a single major with a specified minor range.
90 1da177e4SLinus Torvalds *
91 d358b173SChengguang Xu * If major == 0 this function will dynamically allocate an unused major.
92 d358b173SChengguang Xu * If major > 0 this function will attempt to reserve the range of minors
93 d358b173SChengguang Xu * with given major.
94 1da177e4SLinus Torvalds *
95 1da177e4SLinus Torvalds */
96 1da177e4SLinus Torvalds static struct char_device_struct *
__register_chrdev_region(unsigned int major,unsigned int baseminor,int minorct,const char * name)97 1da177e4SLinus Torvalds __register_chrdev_region(unsigned int major, unsigned int baseminor,
98 1da177e4SLinus Torvalds int minorct, const char *name)
99 1da177e4SLinus Torvalds {
100 4b0be572SChengguang Xu struct char_device_struct *cd, *curr, *prev = NULL;
101 7ef0b152SChengguang Xu int ret;
102 1da177e4SLinus Torvalds int i;
103 1da177e4SLinus Torvalds
104 4b0be572SChengguang Xu if (major >= CHRDEV_MAJOR_MAX) {
105 4b0be572SChengguang Xu pr_err("CHRDEV \"%s\" major requested (%u) is greater than the maximum (%u)\n",
106 4b0be572SChengguang Xu name, major, CHRDEV_MAJOR_MAX-1);
107 4b0be572SChengguang Xu return ERR_PTR(-EINVAL);
108 4b0be572SChengguang Xu }
109 4b0be572SChengguang Xu
110 4712d379SChengguang Xu if (minorct > MINORMASK + 1 - baseminor) {
111 4712d379SChengguang Xu pr_err("CHRDEV \"%s\" minor range requested (%u-%u) is out of range of maximum range (%u-%u) for a single major\n",
112 4712d379SChengguang Xu name, baseminor, baseminor + minorct - 1, 0, MINORMASK);
113 4712d379SChengguang Xu return ERR_PTR(-EINVAL);
114 4712d379SChengguang Xu }
115 4712d379SChengguang Xu
116 11b0b5abSOliver Neukum cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
117 1da177e4SLinus Torvalds if (cd == NULL)
118 1da177e4SLinus Torvalds return ERR_PTR(-ENOMEM);
119 1da177e4SLinus Torvalds
120 58383af6SJes Sorensen mutex_lock(&chrdevs_lock);
121 1da177e4SLinus Torvalds
122 1da177e4SLinus Torvalds if (major == 0) {
123 a5d31a3fSLogan Gunthorpe ret = find_dynamic_major();
124 a5d31a3fSLogan Gunthorpe if (ret < 0) {
125 a5d31a3fSLogan Gunthorpe pr_err("CHRDEV \"%s\" dynamic allocation region is full\n",
126 a5d31a3fSLogan Gunthorpe name);
127 1da177e4SLinus Torvalds goto out;
128 1da177e4SLinus Torvalds }
129 a5d31a3fSLogan Gunthorpe major = ret;
130 1da177e4SLinus Torvalds }
131 1da177e4SLinus Torvalds
132 7ef0b152SChengguang Xu ret = -EBUSY;
133 4b0be572SChengguang Xu i = major_to_index(major);
134 4b0be572SChengguang Xu for (curr = chrdevs[i]; curr; prev = curr, curr = curr->next) {
135 4b0be572SChengguang Xu if (curr->major < major)
136 4b0be572SChengguang Xu continue;
137 4b0be572SChengguang Xu
138 4b0be572SChengguang Xu if (curr->major > major)
139 4b0be572SChengguang Xu break;
140 4b0be572SChengguang Xu
141 4b0be572SChengguang Xu if (curr->baseminor + curr->minorct <= baseminor)
142 4b0be572SChengguang Xu continue;
143 4b0be572SChengguang Xu
144 4b0be572SChengguang Xu if (curr->baseminor >= baseminor + minorct)
145 4b0be572SChengguang Xu break;
146 4b0be572SChengguang Xu
147 8a932f73SLogan Gunthorpe goto out;
148 8a932f73SLogan Gunthorpe }
149 8a932f73SLogan Gunthorpe
150 1da177e4SLinus Torvalds cd->major = major;
151 1da177e4SLinus Torvalds cd->baseminor = baseminor;
152 1da177e4SLinus Torvalds cd->minorct = minorct;
153 *c642256bSAzeem Shaikh strscpy(cd->name, name, sizeof(cd->name));
154 1da177e4SLinus Torvalds
155 4b0be572SChengguang Xu if (!prev) {
156 4b0be572SChengguang Xu cd->next = curr;
157 4b0be572SChengguang Xu chrdevs[i] = cd;
158 4b0be572SChengguang Xu } else {
159 4b0be572SChengguang Xu cd->next = prev->next;
160 4b0be572SChengguang Xu prev->next = cd;
161 1da177e4SLinus Torvalds }
162 01d553d0SAmos Waterland
163 58383af6SJes Sorensen mutex_unlock(&chrdevs_lock);
164 1da177e4SLinus Torvalds return cd;
165 1da177e4SLinus Torvalds out:
166 58383af6SJes Sorensen mutex_unlock(&chrdevs_lock);
167 1da177e4SLinus Torvalds kfree(cd);
168 1da177e4SLinus Torvalds return ERR_PTR(ret);
169 1da177e4SLinus Torvalds }
170 1da177e4SLinus Torvalds
171 1da177e4SLinus Torvalds static struct char_device_struct *
__unregister_chrdev_region(unsigned major,unsigned baseminor,int minorct)172 1da177e4SLinus Torvalds __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
173 1da177e4SLinus Torvalds {
174 1da177e4SLinus Torvalds struct char_device_struct *cd = NULL, **cp;
175 1da177e4SLinus Torvalds int i = major_to_index(major);
176 1da177e4SLinus Torvalds
177 58383af6SJes Sorensen mutex_lock(&chrdevs_lock);
178 1da177e4SLinus Torvalds for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
179 1da177e4SLinus Torvalds if ((*cp)->major == major &&
180 1da177e4SLinus Torvalds (*cp)->baseminor == baseminor &&
181 1da177e4SLinus Torvalds (*cp)->minorct == minorct)
182 1da177e4SLinus Torvalds break;
183 1da177e4SLinus Torvalds if (*cp) {
184 1da177e4SLinus Torvalds cd = *cp;
185 1da177e4SLinus Torvalds *cp = cd->next;
186 1da177e4SLinus Torvalds }
187 58383af6SJes Sorensen mutex_unlock(&chrdevs_lock);
188 1da177e4SLinus Torvalds return cd;
189 1da177e4SLinus Torvalds }
190 1da177e4SLinus Torvalds
191 cf3e43dbSJonathan Corbet /**
192 cf3e43dbSJonathan Corbet * register_chrdev_region() - register a range of device numbers
193 cf3e43dbSJonathan Corbet * @from: the first in the desired range of device numbers; must include
194 cf3e43dbSJonathan Corbet * the major number.
195 cf3e43dbSJonathan Corbet * @count: the number of consecutive device numbers required
196 cf3e43dbSJonathan Corbet * @name: the name of the device or driver.
197 cf3e43dbSJonathan Corbet *
198 cf3e43dbSJonathan Corbet * Return value is zero on success, a negative error code on failure.
199 cf3e43dbSJonathan Corbet */
register_chrdev_region(dev_t from,unsigned count,const char * name)200 1da177e4SLinus Torvalds int register_chrdev_region(dev_t from, unsigned count, const char *name)
201 1da177e4SLinus Torvalds {
202 1da177e4SLinus Torvalds struct char_device_struct *cd;
203 1da177e4SLinus Torvalds dev_t to = from + count;
204 1da177e4SLinus Torvalds dev_t n, next;
205 1da177e4SLinus Torvalds
206 1da177e4SLinus Torvalds for (n = from; n < to; n = next) {
207 1da177e4SLinus Torvalds next = MKDEV(MAJOR(n)+1, 0);
208 1da177e4SLinus Torvalds if (next > to)
209 1da177e4SLinus Torvalds next = to;
210 1da177e4SLinus Torvalds cd = __register_chrdev_region(MAJOR(n), MINOR(n),
211 1da177e4SLinus Torvalds next - n, name);
212 1da177e4SLinus Torvalds if (IS_ERR(cd))
213 1da177e4SLinus Torvalds goto fail;
214 1da177e4SLinus Torvalds }
215 1da177e4SLinus Torvalds return 0;
216 1da177e4SLinus Torvalds fail:
217 1da177e4SLinus Torvalds to = n;
218 1da177e4SLinus Torvalds for (n = from; n < to; n = next) {
219 1da177e4SLinus Torvalds next = MKDEV(MAJOR(n)+1, 0);
220 1da177e4SLinus Torvalds kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
221 1da177e4SLinus Torvalds }
222 1da177e4SLinus Torvalds return PTR_ERR(cd);
223 1da177e4SLinus Torvalds }
224 1da177e4SLinus Torvalds
225 cf3e43dbSJonathan Corbet /**
226 cf3e43dbSJonathan Corbet * alloc_chrdev_region() - register a range of char device numbers
227 cf3e43dbSJonathan Corbet * @dev: output parameter for first assigned number
228 cf3e43dbSJonathan Corbet * @baseminor: first of the requested range of minor numbers
229 cf3e43dbSJonathan Corbet * @count: the number of minor numbers required
230 cf3e43dbSJonathan Corbet * @name: the name of the associated device or driver
231 cf3e43dbSJonathan Corbet *
232 cf3e43dbSJonathan Corbet * Allocates a range of char device numbers. The major number will be
233 cf3e43dbSJonathan Corbet * chosen dynamically, and returned (along with the first minor number)
234 cf3e43dbSJonathan Corbet * in @dev. Returns zero or a negative error code.
235 cf3e43dbSJonathan Corbet */
alloc_chrdev_region(dev_t * dev,unsigned baseminor,unsigned count,const char * name)236 1da177e4SLinus Torvalds int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
237 1da177e4SLinus Torvalds const char *name)
238 1da177e4SLinus Torvalds {
239 1da177e4SLinus Torvalds struct char_device_struct *cd;
240 1da177e4SLinus Torvalds cd = __register_chrdev_region(0, baseminor, count, name);
241 1da177e4SLinus Torvalds if (IS_ERR(cd))
242 1da177e4SLinus Torvalds return PTR_ERR(cd);
243 1da177e4SLinus Torvalds *dev = MKDEV(cd->major, cd->baseminor);
244 1da177e4SLinus Torvalds return 0;
245 1da177e4SLinus Torvalds }
246 1da177e4SLinus Torvalds
247 d247e2c6SRolf Eike Beer /**
248 1905b1bfSTejun Heo * __register_chrdev() - create and register a cdev occupying a range of minors
249 d247e2c6SRolf Eike Beer * @major: major device number or 0 for dynamic allocation
250 1905b1bfSTejun Heo * @baseminor: first of the requested range of minor numbers
251 1905b1bfSTejun Heo * @count: the number of minor numbers required
252 d247e2c6SRolf Eike Beer * @name: name of this range of devices
253 d247e2c6SRolf Eike Beer * @fops: file operations associated with this devices
254 d247e2c6SRolf Eike Beer *
255 d247e2c6SRolf Eike Beer * If @major == 0 this functions will dynamically allocate a major and return
256 d247e2c6SRolf Eike Beer * its number.
257 d247e2c6SRolf Eike Beer *
258 d247e2c6SRolf Eike Beer * If @major > 0 this function will attempt to reserve a device with the given
259 d247e2c6SRolf Eike Beer * major number and will return zero on success.
260 d247e2c6SRolf Eike Beer *
261 d247e2c6SRolf Eike Beer * Returns a -ve errno on failure.
262 d247e2c6SRolf Eike Beer *
263 d247e2c6SRolf Eike Beer * The name of this device has nothing to do with the name of the device in
264 d247e2c6SRolf Eike Beer * /dev. It only helps to keep track of the different owners of devices. If
265 d247e2c6SRolf Eike Beer * your module name has only one type of devices it's ok to use e.g. the name
266 d247e2c6SRolf Eike Beer * of the module here.
267 d247e2c6SRolf Eike Beer */
__register_chrdev(unsigned int major,unsigned int baseminor,unsigned int count,const char * name,const struct file_operations * fops)268 1905b1bfSTejun Heo int __register_chrdev(unsigned int major, unsigned int baseminor,
269 1905b1bfSTejun Heo unsigned int count, const char *name,
270 99ac48f5SArjan van de Ven const struct file_operations *fops)
271 1da177e4SLinus Torvalds {
272 1da177e4SLinus Torvalds struct char_device_struct *cd;
273 1da177e4SLinus Torvalds struct cdev *cdev;
274 1da177e4SLinus Torvalds int err = -ENOMEM;
275 1da177e4SLinus Torvalds
276 1905b1bfSTejun Heo cd = __register_chrdev_region(major, baseminor, count, name);
277 1da177e4SLinus Torvalds if (IS_ERR(cd))
278 1da177e4SLinus Torvalds return PTR_ERR(cd);
279 1da177e4SLinus Torvalds
280 1da177e4SLinus Torvalds cdev = cdev_alloc();
281 1da177e4SLinus Torvalds if (!cdev)
282 1da177e4SLinus Torvalds goto out2;
283 1da177e4SLinus Torvalds
284 1da177e4SLinus Torvalds cdev->owner = fops->owner;
285 1da177e4SLinus Torvalds cdev->ops = fops;
286 1da177e4SLinus Torvalds kobject_set_name(&cdev->kobj, "%s", name);
287 1da177e4SLinus Torvalds
288 1905b1bfSTejun Heo err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);
289 1da177e4SLinus Torvalds if (err)
290 1da177e4SLinus Torvalds goto out;
291 1da177e4SLinus Torvalds
292 1da177e4SLinus Torvalds cd->cdev = cdev;
293 1da177e4SLinus Torvalds
294 1da177e4SLinus Torvalds return major ? 0 : cd->major;
295 1da177e4SLinus Torvalds out:
296 1da177e4SLinus Torvalds kobject_put(&cdev->kobj);
297 1da177e4SLinus Torvalds out2:
298 1905b1bfSTejun Heo kfree(__unregister_chrdev_region(cd->major, baseminor, count));
299 1da177e4SLinus Torvalds return err;
300 1da177e4SLinus Torvalds }
301 1da177e4SLinus Torvalds
302 cf3e43dbSJonathan Corbet /**
303 594069bcSPartha Pratim Mukherjee * unregister_chrdev_region() - unregister a range of device numbers
304 cf3e43dbSJonathan Corbet * @from: the first in the range of numbers to unregister
305 cf3e43dbSJonathan Corbet * @count: the number of device numbers to unregister
306 cf3e43dbSJonathan Corbet *
307 cf3e43dbSJonathan Corbet * This function will unregister a range of @count device numbers,
308 cf3e43dbSJonathan Corbet * starting with @from. The caller should normally be the one who
309 cf3e43dbSJonathan Corbet * allocated those numbers in the first place...
310 cf3e43dbSJonathan Corbet */
unregister_chrdev_region(dev_t from,unsigned count)311 1da177e4SLinus Torvalds void unregister_chrdev_region(dev_t from, unsigned count)
312 1da177e4SLinus Torvalds {
313 1da177e4SLinus Torvalds dev_t to = from + count;
314 1da177e4SLinus Torvalds dev_t n, next;
315 1da177e4SLinus Torvalds
316 1da177e4SLinus Torvalds for (n = from; n < to; n = next) {
317 1da177e4SLinus Torvalds next = MKDEV(MAJOR(n)+1, 0);
318 1da177e4SLinus Torvalds if (next > to)
319 1da177e4SLinus Torvalds next = to;
320 1da177e4SLinus Torvalds kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
321 1da177e4SLinus Torvalds }
322 1da177e4SLinus Torvalds }
323 1da177e4SLinus Torvalds
324 1905b1bfSTejun Heo /**
325 1905b1bfSTejun Heo * __unregister_chrdev - unregister and destroy a cdev
326 1905b1bfSTejun Heo * @major: major device number
327 1905b1bfSTejun Heo * @baseminor: first of the range of minor numbers
328 1905b1bfSTejun Heo * @count: the number of minor numbers this cdev is occupying
329 1905b1bfSTejun Heo * @name: name of this range of devices
330 1905b1bfSTejun Heo *
331 1905b1bfSTejun Heo * Unregister and destroy the cdev occupying the region described by
332 1905b1bfSTejun Heo * @major, @baseminor and @count. This function undoes what
333 1905b1bfSTejun Heo * __register_chrdev() did.
334 1905b1bfSTejun Heo */
__unregister_chrdev(unsigned int major,unsigned int baseminor,unsigned int count,const char * name)335 1905b1bfSTejun Heo void __unregister_chrdev(unsigned int major, unsigned int baseminor,
336 1905b1bfSTejun Heo unsigned int count, const char *name)
337 1da177e4SLinus Torvalds {
338 1da177e4SLinus Torvalds struct char_device_struct *cd;
339 1905b1bfSTejun Heo
340 1905b1bfSTejun Heo cd = __unregister_chrdev_region(major, baseminor, count);
341 1da177e4SLinus Torvalds if (cd && cd->cdev)
342 1da177e4SLinus Torvalds cdev_del(cd->cdev);
343 1da177e4SLinus Torvalds kfree(cd);
344 1da177e4SLinus Torvalds }
345 1da177e4SLinus Torvalds
346 1da177e4SLinus Torvalds static DEFINE_SPINLOCK(cdev_lock);
347 1da177e4SLinus Torvalds
cdev_get(struct cdev * p)348 1da177e4SLinus Torvalds static struct kobject *cdev_get(struct cdev *p)
349 1da177e4SLinus Torvalds {
350 1da177e4SLinus Torvalds struct module *owner = p->owner;
351 1da177e4SLinus Torvalds struct kobject *kobj;
352 1da177e4SLinus Torvalds
353 1da177e4SLinus Torvalds if (owner && !try_module_get(owner))
354 1da177e4SLinus Torvalds return NULL;
355 68faa679SWill Deacon kobj = kobject_get_unless_zero(&p->kobj);
356 1da177e4SLinus Torvalds if (!kobj)
357 1da177e4SLinus Torvalds module_put(owner);
358 1da177e4SLinus Torvalds return kobj;
359 1da177e4SLinus Torvalds }
360 1da177e4SLinus Torvalds
cdev_put(struct cdev * p)361 1da177e4SLinus Torvalds void cdev_put(struct cdev *p)
362 1da177e4SLinus Torvalds {
363 1da177e4SLinus Torvalds if (p) {
364 7da6844cSBrian King struct module *owner = p->owner;
365 1da177e4SLinus Torvalds kobject_put(&p->kobj);
366 7da6844cSBrian King module_put(owner);
367 1da177e4SLinus Torvalds }
368 1da177e4SLinus Torvalds }
369 1da177e4SLinus Torvalds
370 1da177e4SLinus Torvalds /*
371 1da177e4SLinus Torvalds * Called every time a character special file is opened
372 1da177e4SLinus Torvalds */
chrdev_open(struct inode * inode,struct file * filp)373 922f9cfaSDenis Cheng static int chrdev_open(struct inode *inode, struct file *filp)
374 1da177e4SLinus Torvalds {
375 e84f9e57SAl Viro const struct file_operations *fops;
376 1da177e4SLinus Torvalds struct cdev *p;
377 1da177e4SLinus Torvalds struct cdev *new = NULL;
378 1da177e4SLinus Torvalds int ret = 0;
379 1da177e4SLinus Torvalds
380 1da177e4SLinus Torvalds spin_lock(&cdev_lock);
381 1da177e4SLinus Torvalds p = inode->i_cdev;
382 1da177e4SLinus Torvalds if (!p) {
383 1da177e4SLinus Torvalds struct kobject *kobj;
384 1da177e4SLinus Torvalds int idx;
385 1da177e4SLinus Torvalds spin_unlock(&cdev_lock);
386 1da177e4SLinus Torvalds kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
387 1da177e4SLinus Torvalds if (!kobj)
388 1da177e4SLinus Torvalds return -ENXIO;
389 1da177e4SLinus Torvalds new = container_of(kobj, struct cdev, kobj);
390 1da177e4SLinus Torvalds spin_lock(&cdev_lock);
391 a30427d9SJonathan Corbet /* Check i_cdev again in case somebody beat us to it while
392 a30427d9SJonathan Corbet we dropped the lock. */
393 1da177e4SLinus Torvalds p = inode->i_cdev;
394 1da177e4SLinus Torvalds if (!p) {
395 1da177e4SLinus Torvalds inode->i_cdev = p = new;
396 1da177e4SLinus Torvalds list_add(&inode->i_devices, &p->list);
397 1da177e4SLinus Torvalds new = NULL;
398 1da177e4SLinus Torvalds } else if (!cdev_get(p))
399 1da177e4SLinus Torvalds ret = -ENXIO;
400 1da177e4SLinus Torvalds } else if (!cdev_get(p))
401 1da177e4SLinus Torvalds ret = -ENXIO;
402 1da177e4SLinus Torvalds spin_unlock(&cdev_lock);
403 1da177e4SLinus Torvalds cdev_put(new);
404 1da177e4SLinus Torvalds if (ret)
405 1da177e4SLinus Torvalds return ret;
406 a518ab93SChristoph Hellwig
407 a518ab93SChristoph Hellwig ret = -ENXIO;
408 e84f9e57SAl Viro fops = fops_get(p->ops);
409 e84f9e57SAl Viro if (!fops)
410 a518ab93SChristoph Hellwig goto out_cdev_put;
411 a518ab93SChristoph Hellwig
412 e84f9e57SAl Viro replace_fops(filp, fops);
413 a518ab93SChristoph Hellwig if (filp->f_op->open) {
414 1da177e4SLinus Torvalds ret = filp->f_op->open(inode, filp);
415 1da177e4SLinus Torvalds if (ret)
416 a518ab93SChristoph Hellwig goto out_cdev_put;
417 a518ab93SChristoph Hellwig }
418 a518ab93SChristoph Hellwig
419 a518ab93SChristoph Hellwig return 0;
420 a518ab93SChristoph Hellwig
421 a518ab93SChristoph Hellwig out_cdev_put:
422 1da177e4SLinus Torvalds cdev_put(p);
423 1da177e4SLinus Torvalds return ret;
424 1da177e4SLinus Torvalds }
425 1da177e4SLinus Torvalds
cd_forget(struct inode * inode)426 1da177e4SLinus Torvalds void cd_forget(struct inode *inode)
427 1da177e4SLinus Torvalds {
428 1da177e4SLinus Torvalds spin_lock(&cdev_lock);
429 1da177e4SLinus Torvalds list_del_init(&inode->i_devices);
430 1da177e4SLinus Torvalds inode->i_cdev = NULL;
431 3bc52c45SDan Williams inode->i_mapping = &inode->i_data;
432 1da177e4SLinus Torvalds spin_unlock(&cdev_lock);
433 1da177e4SLinus Torvalds }
434 1da177e4SLinus Torvalds
cdev_purge(struct cdev * cdev)435 75c96f85SAdrian Bunk static void cdev_purge(struct cdev *cdev)
436 1da177e4SLinus Torvalds {
437 1da177e4SLinus Torvalds spin_lock(&cdev_lock);
438 1da177e4SLinus Torvalds while (!list_empty(&cdev->list)) {
439 1da177e4SLinus Torvalds struct inode *inode;
440 1da177e4SLinus Torvalds inode = container_of(cdev->list.next, struct inode, i_devices);
441 1da177e4SLinus Torvalds list_del_init(&inode->i_devices);
442 1da177e4SLinus Torvalds inode->i_cdev = NULL;
443 1da177e4SLinus Torvalds }
444 1da177e4SLinus Torvalds spin_unlock(&cdev_lock);
445 1da177e4SLinus Torvalds }
446 1da177e4SLinus Torvalds
447 1da177e4SLinus Torvalds /*
448 1da177e4SLinus Torvalds * Dummy default file-operations: the only thing this does
449 1da177e4SLinus Torvalds * is contain the open that then fills in the correct operations
450 1da177e4SLinus Torvalds * depending on the special file...
451 1da177e4SLinus Torvalds */
452 4b6f5d20SArjan van de Ven const struct file_operations def_chr_fops = {
453 1da177e4SLinus Torvalds .open = chrdev_open,
454 6038f373SArnd Bergmann .llseek = noop_llseek,
455 1da177e4SLinus Torvalds };
456 1da177e4SLinus Torvalds
exact_match(dev_t dev,int * part,void * data)457 1da177e4SLinus Torvalds static struct kobject *exact_match(dev_t dev, int *part, void *data)
458 1da177e4SLinus Torvalds {
459 1da177e4SLinus Torvalds struct cdev *p = data;
460 1da177e4SLinus Torvalds return &p->kobj;
461 1da177e4SLinus Torvalds }
462 1da177e4SLinus Torvalds
exact_lock(dev_t dev,void * data)463 1da177e4SLinus Torvalds static int exact_lock(dev_t dev, void *data)
464 1da177e4SLinus Torvalds {
465 1da177e4SLinus Torvalds struct cdev *p = data;
466 1da177e4SLinus Torvalds return cdev_get(p) ? 0 : -1;
467 1da177e4SLinus Torvalds }
468 1da177e4SLinus Torvalds
469 cf3e43dbSJonathan Corbet /**
470 cf3e43dbSJonathan Corbet * cdev_add() - add a char device to the system
471 cf3e43dbSJonathan Corbet * @p: the cdev structure for the device
472 cf3e43dbSJonathan Corbet * @dev: the first device number for which this device is responsible
473 cf3e43dbSJonathan Corbet * @count: the number of consecutive minor numbers corresponding to this
474 cf3e43dbSJonathan Corbet * device
475 cf3e43dbSJonathan Corbet *
476 cf3e43dbSJonathan Corbet * cdev_add() adds the device represented by @p to the system, making it
477 cf3e43dbSJonathan Corbet * live immediately. A negative error code is returned on failure.
478 cf3e43dbSJonathan Corbet */
cdev_add(struct cdev * p,dev_t dev,unsigned count)479 1da177e4SLinus Torvalds int cdev_add(struct cdev *p, dev_t dev, unsigned count)
480 1da177e4SLinus Torvalds {
481 2f0157f1SDmitry Torokhov int error;
482 2f0157f1SDmitry Torokhov
483 1da177e4SLinus Torvalds p->dev = dev;
484 1da177e4SLinus Torvalds p->count = count;
485 2f0157f1SDmitry Torokhov
486 4634c973SShang XiaoJing if (WARN_ON(dev == WHITEOUT_DEV)) {
487 4634c973SShang XiaoJing error = -EBUSY;
488 4634c973SShang XiaoJing goto err;
489 4634c973SShang XiaoJing }
490 a3c751a5SMiklos Szeredi
491 2f0157f1SDmitry Torokhov error = kobj_map(cdev_map, dev, count, NULL,
492 2f0157f1SDmitry Torokhov exact_match, exact_lock, p);
493 2f0157f1SDmitry Torokhov if (error)
494 4634c973SShang XiaoJing goto err;
495 2f0157f1SDmitry Torokhov
496 2f0157f1SDmitry Torokhov kobject_get(p->kobj.parent);
497 2f0157f1SDmitry Torokhov
498 2f0157f1SDmitry Torokhov return 0;
499 4634c973SShang XiaoJing
500 4634c973SShang XiaoJing err:
501 4634c973SShang XiaoJing kfree_const(p->kobj.name);
502 4634c973SShang XiaoJing p->kobj.name = NULL;
503 4634c973SShang XiaoJing return error;
504 1da177e4SLinus Torvalds }
505 1da177e4SLinus Torvalds
506 233ed09dSLogan Gunthorpe /**
507 233ed09dSLogan Gunthorpe * cdev_set_parent() - set the parent kobject for a char device
508 233ed09dSLogan Gunthorpe * @p: the cdev structure
509 233ed09dSLogan Gunthorpe * @kobj: the kobject to take a reference to
510 233ed09dSLogan Gunthorpe *
511 233ed09dSLogan Gunthorpe * cdev_set_parent() sets a parent kobject which will be referenced
512 233ed09dSLogan Gunthorpe * appropriately so the parent is not freed before the cdev. This
513 233ed09dSLogan Gunthorpe * should be called before cdev_add.
514 233ed09dSLogan Gunthorpe */
cdev_set_parent(struct cdev * p,struct kobject * kobj)515 233ed09dSLogan Gunthorpe void cdev_set_parent(struct cdev *p, struct kobject *kobj)
516 233ed09dSLogan Gunthorpe {
517 233ed09dSLogan Gunthorpe WARN_ON(!kobj->state_initialized);
518 233ed09dSLogan Gunthorpe p->kobj.parent = kobj;
519 233ed09dSLogan Gunthorpe }
520 233ed09dSLogan Gunthorpe
521 233ed09dSLogan Gunthorpe /**
522 233ed09dSLogan Gunthorpe * cdev_device_add() - add a char device and it's corresponding
523 233ed09dSLogan Gunthorpe * struct device, linkink
524 233ed09dSLogan Gunthorpe * @dev: the device structure
525 233ed09dSLogan Gunthorpe * @cdev: the cdev structure
526 233ed09dSLogan Gunthorpe *
527 233ed09dSLogan Gunthorpe * cdev_device_add() adds the char device represented by @cdev to the system,
528 233ed09dSLogan Gunthorpe * just as cdev_add does. It then adds @dev to the system using device_add
529 233ed09dSLogan Gunthorpe * The dev_t for the char device will be taken from the struct device which
530 233ed09dSLogan Gunthorpe * needs to be initialized first. This helper function correctly takes a
531 233ed09dSLogan Gunthorpe * reference to the parent device so the parent will not get released until
532 233ed09dSLogan Gunthorpe * all references to the cdev are released.
533 233ed09dSLogan Gunthorpe *
534 233ed09dSLogan Gunthorpe * This helper uses dev->devt for the device number. If it is not set
535 233ed09dSLogan Gunthorpe * it will not add the cdev and it will be equivalent to device_add.
536 233ed09dSLogan Gunthorpe *
537 233ed09dSLogan Gunthorpe * This function should be used whenever the struct cdev and the
538 233ed09dSLogan Gunthorpe * struct device are members of the same structure whose lifetime is
539 233ed09dSLogan Gunthorpe * managed by the struct device.
540 233ed09dSLogan Gunthorpe *
541 233ed09dSLogan Gunthorpe * NOTE: Callers must assume that userspace was able to open the cdev and
542 233ed09dSLogan Gunthorpe * can call cdev fops callbacks at any time, even if this function fails.
543 233ed09dSLogan Gunthorpe */
cdev_device_add(struct cdev * cdev,struct device * dev)544 233ed09dSLogan Gunthorpe int cdev_device_add(struct cdev *cdev, struct device *dev)
545 233ed09dSLogan Gunthorpe {
546 233ed09dSLogan Gunthorpe int rc = 0;
547 233ed09dSLogan Gunthorpe
548 233ed09dSLogan Gunthorpe if (dev->devt) {
549 233ed09dSLogan Gunthorpe cdev_set_parent(cdev, &dev->kobj);
550 233ed09dSLogan Gunthorpe
551 233ed09dSLogan Gunthorpe rc = cdev_add(cdev, dev->devt, 1);
552 233ed09dSLogan Gunthorpe if (rc)
553 233ed09dSLogan Gunthorpe return rc;
554 233ed09dSLogan Gunthorpe }
555 233ed09dSLogan Gunthorpe
556 233ed09dSLogan Gunthorpe rc = device_add(dev);
557 11fa7fefSYang Yingliang if (rc && dev->devt)
558 233ed09dSLogan Gunthorpe cdev_del(cdev);
559 233ed09dSLogan Gunthorpe
560 233ed09dSLogan Gunthorpe return rc;
561 233ed09dSLogan Gunthorpe }
562 233ed09dSLogan Gunthorpe
563 233ed09dSLogan Gunthorpe /**
564 233ed09dSLogan Gunthorpe * cdev_device_del() - inverse of cdev_device_add
565 233ed09dSLogan Gunthorpe * @dev: the device structure
566 233ed09dSLogan Gunthorpe * @cdev: the cdev structure
567 233ed09dSLogan Gunthorpe *
568 233ed09dSLogan Gunthorpe * cdev_device_del() is a helper function to call cdev_del and device_del.
569 233ed09dSLogan Gunthorpe * It should be used whenever cdev_device_add is used.
570 233ed09dSLogan Gunthorpe *
571 233ed09dSLogan Gunthorpe * If dev->devt is not set it will not remove the cdev and will be equivalent
572 233ed09dSLogan Gunthorpe * to device_del.
573 233ed09dSLogan Gunthorpe *
574 233ed09dSLogan Gunthorpe * NOTE: This guarantees that associated sysfs callbacks are not running
575 233ed09dSLogan Gunthorpe * or runnable, however any cdevs already open will remain and their fops
576 233ed09dSLogan Gunthorpe * will still be callable even after this function returns.
577 233ed09dSLogan Gunthorpe */
cdev_device_del(struct cdev * cdev,struct device * dev)578 233ed09dSLogan Gunthorpe void cdev_device_del(struct cdev *cdev, struct device *dev)
579 233ed09dSLogan Gunthorpe {
580 233ed09dSLogan Gunthorpe device_del(dev);
581 233ed09dSLogan Gunthorpe if (dev->devt)
582 233ed09dSLogan Gunthorpe cdev_del(cdev);
583 233ed09dSLogan Gunthorpe }
584 233ed09dSLogan Gunthorpe
cdev_unmap(dev_t dev,unsigned count)585 1da177e4SLinus Torvalds static void cdev_unmap(dev_t dev, unsigned count)
586 1da177e4SLinus Torvalds {
587 1da177e4SLinus Torvalds kobj_unmap(cdev_map, dev, count);
588 1da177e4SLinus Torvalds }
589 1da177e4SLinus Torvalds
590 cf3e43dbSJonathan Corbet /**
591 cf3e43dbSJonathan Corbet * cdev_del() - remove a cdev from the system
592 cf3e43dbSJonathan Corbet * @p: the cdev structure to be removed
593 cf3e43dbSJonathan Corbet *
594 cf3e43dbSJonathan Corbet * cdev_del() removes @p from the system, possibly freeing the structure
595 cf3e43dbSJonathan Corbet * itself.
596 233ed09dSLogan Gunthorpe *
597 233ed09dSLogan Gunthorpe * NOTE: This guarantees that cdev device will no longer be able to be
598 233ed09dSLogan Gunthorpe * opened, however any cdevs already open will remain and their fops will
599 233ed09dSLogan Gunthorpe * still be callable even after cdev_del returns.
600 cf3e43dbSJonathan Corbet */
cdev_del(struct cdev * p)601 1da177e4SLinus Torvalds void cdev_del(struct cdev *p)
602 1da177e4SLinus Torvalds {
603 1da177e4SLinus Torvalds cdev_unmap(p->dev, p->count);
604 1da177e4SLinus Torvalds kobject_put(&p->kobj);
605 1da177e4SLinus Torvalds }
606 1da177e4SLinus Torvalds
607 1da177e4SLinus Torvalds
cdev_default_release(struct kobject * kobj)608 1da177e4SLinus Torvalds static void cdev_default_release(struct kobject *kobj)
609 1da177e4SLinus Torvalds {
610 1da177e4SLinus Torvalds struct cdev *p = container_of(kobj, struct cdev, kobj);
611 2f0157f1SDmitry Torokhov struct kobject *parent = kobj->parent;
612 2f0157f1SDmitry Torokhov
613 1da177e4SLinus Torvalds cdev_purge(p);
614 2f0157f1SDmitry Torokhov kobject_put(parent);
615 1da177e4SLinus Torvalds }
616 1da177e4SLinus Torvalds
cdev_dynamic_release(struct kobject * kobj)617 1da177e4SLinus Torvalds static void cdev_dynamic_release(struct kobject *kobj)
618 1da177e4SLinus Torvalds {
619 1da177e4SLinus Torvalds struct cdev *p = container_of(kobj, struct cdev, kobj);
620 2f0157f1SDmitry Torokhov struct kobject *parent = kobj->parent;
621 2f0157f1SDmitry Torokhov
622 1da177e4SLinus Torvalds cdev_purge(p);
623 1da177e4SLinus Torvalds kfree(p);
624 2f0157f1SDmitry Torokhov kobject_put(parent);
625 1da177e4SLinus Torvalds }
626 1da177e4SLinus Torvalds
627 1da177e4SLinus Torvalds static struct kobj_type ktype_cdev_default = {
628 1da177e4SLinus Torvalds .release = cdev_default_release,
629 1da177e4SLinus Torvalds };
630 1da177e4SLinus Torvalds
631 1da177e4SLinus Torvalds static struct kobj_type ktype_cdev_dynamic = {
632 1da177e4SLinus Torvalds .release = cdev_dynamic_release,
633 1da177e4SLinus Torvalds };
634 1da177e4SLinus Torvalds
635 cf3e43dbSJonathan Corbet /**
636 cf3e43dbSJonathan Corbet * cdev_alloc() - allocate a cdev structure
637 cf3e43dbSJonathan Corbet *
638 cf3e43dbSJonathan Corbet * Allocates and returns a cdev structure, or NULL on failure.
639 cf3e43dbSJonathan Corbet */
cdev_alloc(void)640 1da177e4SLinus Torvalds struct cdev *cdev_alloc(void)
641 1da177e4SLinus Torvalds {
642 11b0b5abSOliver Neukum struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
643 1da177e4SLinus Torvalds if (p) {
644 1da177e4SLinus Torvalds INIT_LIST_HEAD(&p->list);
645 f9cb074bSGreg Kroah-Hartman kobject_init(&p->kobj, &ktype_cdev_dynamic);
646 1da177e4SLinus Torvalds }
647 1da177e4SLinus Torvalds return p;
648 1da177e4SLinus Torvalds }
649 1da177e4SLinus Torvalds
650 cf3e43dbSJonathan Corbet /**
651 cf3e43dbSJonathan Corbet * cdev_init() - initialize a cdev structure
652 cf3e43dbSJonathan Corbet * @cdev: the structure to initialize
653 cf3e43dbSJonathan Corbet * @fops: the file_operations for this device
654 cf3e43dbSJonathan Corbet *
655 cf3e43dbSJonathan Corbet * Initializes @cdev, remembering @fops, making it ready to add to the
656 cf3e43dbSJonathan Corbet * system with cdev_add().
657 cf3e43dbSJonathan Corbet */
cdev_init(struct cdev * cdev,const struct file_operations * fops)658 99ac48f5SArjan van de Ven void cdev_init(struct cdev *cdev, const struct file_operations *fops)
659 1da177e4SLinus Torvalds {
660 1da177e4SLinus Torvalds memset(cdev, 0, sizeof *cdev);
661 1da177e4SLinus Torvalds INIT_LIST_HEAD(&cdev->list);
662 f9cb074bSGreg Kroah-Hartman kobject_init(&cdev->kobj, &ktype_cdev_default);
663 1da177e4SLinus Torvalds cdev->ops = fops;
664 1da177e4SLinus Torvalds }
665 1da177e4SLinus Torvalds
base_probe(dev_t dev,int * part,void * data)666 1da177e4SLinus Torvalds static struct kobject *base_probe(dev_t dev, int *part, void *data)
667 1da177e4SLinus Torvalds {
668 1da177e4SLinus Torvalds if (request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev)) > 0)
669 1da177e4SLinus Torvalds /* Make old-style 2.4 aliases work */
670 1da177e4SLinus Torvalds request_module("char-major-%d", MAJOR(dev));
671 1da177e4SLinus Torvalds return NULL;
672 1da177e4SLinus Torvalds }
673 1da177e4SLinus Torvalds
chrdev_init(void)674 1da177e4SLinus Torvalds void __init chrdev_init(void)
675 1da177e4SLinus Torvalds {
676 1da177e4SLinus Torvalds cdev_map = kobj_map_init(base_probe, &chrdevs_lock);
677 1da177e4SLinus Torvalds }
678 1da177e4SLinus Torvalds
679 1da177e4SLinus Torvalds
680 1da177e4SLinus Torvalds /* Let modules do char dev stuff */
681 1da177e4SLinus Torvalds EXPORT_SYMBOL(register_chrdev_region);
682 1da177e4SLinus Torvalds EXPORT_SYMBOL(unregister_chrdev_region);
683 1da177e4SLinus Torvalds EXPORT_SYMBOL(alloc_chrdev_region);
684 1da177e4SLinus Torvalds EXPORT_SYMBOL(cdev_init);
685 1da177e4SLinus Torvalds EXPORT_SYMBOL(cdev_alloc);
686 1da177e4SLinus Torvalds EXPORT_SYMBOL(cdev_del);
687 1da177e4SLinus Torvalds EXPORT_SYMBOL(cdev_add);
688 233ed09dSLogan Gunthorpe EXPORT_SYMBOL(cdev_set_parent);
689 233ed09dSLogan Gunthorpe EXPORT_SYMBOL(cdev_device_add);
690 233ed09dSLogan Gunthorpe EXPORT_SYMBOL(cdev_device_del);
691 1905b1bfSTejun Heo EXPORT_SYMBOL(__register_chrdev);
692 1905b1bfSTejun Heo EXPORT_SYMBOL(__unregister_chrdev);
693