Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
char
misc.c
Go to the documentation of this file.
1
/*
2
* linux/drivers/char/misc.c
3
*
4
* Generic misc open routine by Johan Myreen
5
*
6
* Based on code from Linus
7
*
8
* Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
9
* changes incorporated into 0.97pl4
10
* by Peter Cervasio (pete%
[email protected]
) (08SEP92)
11
* See busmouse.c for particulars.
12
*
13
* Made things a lot mode modular - easy to compile in just one or two
14
* of the misc drivers, as they are now completely independent. Linus.
15
*
16
* Support for loadable modules. 8-Sep-95 Philip Blundell <
[email protected]
>
17
*
18
* Fixed a failing symbol register to free the device registration
19
* Alan Cox <
[email protected]
> 21-Jan-96
20
*
21
* Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96
22
*
23
* Renamed to misc and miscdevice to be more accurate. Alan Cox 26-Mar-96
24
*
25
* Handling of mouse minor numbers for kerneld:
26
* Idea by Jacques Gelinas <
[email protected]
>,
27
* adapted by Bjorn Ekwall <
[email protected]
>
28
* corrected by Alan Cox <
[email protected]
>
29
*
30
* Changes for kmod (from kerneld):
31
* Cyrus Durgin <
[email protected]
>
32
*
33
* Added devfs support. Richard Gooch <
[email protected]
> 10-Jan-1998
34
*/
35
36
#include <linux/module.h>
37
38
#include <linux/fs.h>
39
#include <linux/errno.h>
40
#include <
linux/miscdevice.h
>
41
#include <linux/kernel.h>
42
#include <
linux/major.h
>
43
#include <
linux/mutex.h
>
44
#include <
linux/proc_fs.h
>
45
#include <
linux/seq_file.h
>
46
#include <linux/stat.h>
47
#include <
linux/init.h
>
48
#include <linux/device.h>
49
#include <linux/tty.h>
50
#include <
linux/kmod.h
>
51
#include <
linux/gfp.h
>
52
53
/*
54
* Head entry for the doubly linked miscdevice list
55
*/
56
static
LIST_HEAD
(misc_list);
57
static
DEFINE_MUTEX
(misc_mtx);
58
59
/*
60
* Assigned numbers, used for dynamic minors
61
*/
62
#define DYNAMIC_MINORS 64
/* like dynamic majors */
63
static
DECLARE_BITMAP
(misc_minors,
DYNAMIC_MINORS
);
64
65
#ifdef CONFIG_PROC_FS
66
static
void
*misc_seq_start(
struct
seq_file
*seq, loff_t *
pos
)
67
{
68
mutex_lock
(&misc_mtx);
69
return
seq_list_start
(&misc_list, *pos);
70
}
71
72
static
void
*misc_seq_next(
struct
seq_file
*seq,
void
*
v
, loff_t *
pos
)
73
{
74
return
seq_list_next
(v, &misc_list, pos);
75
}
76
77
static
void
misc_seq_stop(
struct
seq_file
*seq,
void
*
v
)
78
{
79
mutex_unlock
(&misc_mtx);
80
}
81
82
static
int
misc_seq_show(
struct
seq_file
*seq,
void
*
v
)
83
{
84
const
struct
miscdevice
*
p
=
list_entry
(v,
struct
miscdevice
,
list
);
85
86
seq_printf
(seq,
"%3i %s\n"
, p->
minor
, p->
name
? p->
name
:
""
);
87
return
0;
88
}
89
90
91
static
const
struct
seq_operations
misc_seq_ops = {
92
.
start
= misc_seq_start,
93
.next = misc_seq_next,
94
.stop = misc_seq_stop,
95
.show = misc_seq_show,
96
};
97
98
static
int
misc_seq_open(
struct
inode
*
inode
,
struct
file
*
file
)
99
{
100
return
seq_open
(file, &misc_seq_ops);
101
}
102
103
static
const
struct
file_operations
misc_proc_fops = {
104
.
owner
=
THIS_MODULE
,
105
.open = misc_seq_open,
106
.read =
seq_read
,
107
.llseek =
seq_lseek
,
108
.release =
seq_release
,
109
};
110
#endif
111
112
static
int
misc_open(
struct
inode
*
inode
,
struct
file
*
file
)
113
{
114
int
minor
= iminor(inode);
115
struct
miscdevice
*
c
;
116
int
err
= -
ENODEV
;
117
const
struct
file_operations
*old_fops, *new_fops =
NULL
;
118
119
mutex_lock
(&misc_mtx);
120
121
list_for_each_entry
(c, &misc_list,
list
) {
122
if
(c->
minor
== minor) {
123
new_fops =
fops_get
(c->
fops
);
124
break
;
125
}
126
}
127
128
if
(!new_fops) {
129
mutex_unlock
(&misc_mtx);
130
request_module(
"char-major-%d-%d"
,
MISC_MAJOR
, minor);
131
mutex_lock
(&misc_mtx);
132
133
list_for_each_entry
(c, &misc_list,
list
) {
134
if
(c->
minor
== minor) {
135
new_fops =
fops_get
(c->
fops
);
136
break
;
137
}
138
}
139
if
(!new_fops)
140
goto
fail;
141
}
142
143
err = 0;
144
old_fops = file->
f_op
;
145
file->
f_op
= new_fops;
146
if
(file->
f_op
->open) {
147
file->
private_data
=
c
;
148
err=file->
f_op
->open(inode,file);
149
if
(err) {
150
fops_put
(file->
f_op
);
151
file->
f_op
=
fops_get
(old_fops);
152
}
153
}
154
fops_put
(old_fops);
155
fail:
156
mutex_unlock
(&misc_mtx);
157
return
err
;
158
}
159
160
static
struct
class
*misc_class;
161
162
static
const
struct
file_operations
misc_fops = {
163
.owner =
THIS_MODULE
,
164
.open = misc_open,
165
.llseek =
noop_llseek
,
166
};
167
184
int
misc_register
(
struct
miscdevice
* misc)
185
{
186
struct
miscdevice
*
c
;
187
dev_t
dev
;
188
int
err = 0;
189
190
INIT_LIST_HEAD(&misc->
list
);
191
192
mutex_lock
(&misc_mtx);
193
list_for_each_entry
(c, &misc_list,
list
) {
194
if
(c->
minor
== misc->
minor
) {
195
mutex_unlock
(&misc_mtx);
196
return
-
EBUSY
;
197
}
198
}
199
200
if
(misc->
minor
==
MISC_DYNAMIC_MINOR
) {
201
int
i
=
find_first_zero_bit
(misc_minors,
DYNAMIC_MINORS
);
202
if
(i >=
DYNAMIC_MINORS
) {
203
mutex_unlock
(&misc_mtx);
204
return
-
EBUSY
;
205
}
206
misc->
minor
=
DYNAMIC_MINORS
- i - 1;
207
set_bit
(i, misc_minors);
208
}
209
210
dev =
MKDEV
(
MISC_MAJOR
, misc->
minor
);
211
212
misc->
this_device
=
device_create
(misc_class, misc->
parent
, dev,
213
misc,
"%s"
, misc->
name
);
214
if
(IS_ERR(misc->
this_device
)) {
215
int
i
=
DYNAMIC_MINORS
- misc->
minor
- 1;
216
if
(i < DYNAMIC_MINORS && i >= 0)
217
clear_bit
(i, misc_minors);
218
err = PTR_ERR(misc->
this_device
);
219
goto
out
;
220
}
221
222
/*
223
* Add it to the front, so that later devices can "override"
224
* earlier defaults
225
*/
226
list_add(&misc->
list
, &misc_list);
227
out
:
228
mutex_unlock
(&misc_mtx);
229
return
err
;
230
}
231
242
int
misc_deregister
(
struct
miscdevice
*misc)
243
{
244
int
i
=
DYNAMIC_MINORS
- misc->
minor
- 1;
245
246
if
(
WARN_ON
(list_empty(&misc->
list
)))
247
return
-
EINVAL
;
248
249
mutex_lock
(&misc_mtx);
250
list_del
(&misc->
list
);
251
device_destroy
(misc_class,
MKDEV
(
MISC_MAJOR
, misc->
minor
));
252
if
(i < DYNAMIC_MINORS && i >= 0)
253
clear_bit
(i, misc_minors);
254
mutex_unlock
(&misc_mtx);
255
return
0;
256
}
257
258
EXPORT_SYMBOL
(
misc_register
);
259
EXPORT_SYMBOL
(
misc_deregister
);
260
261
static
char
*misc_devnode(
struct
device
*
dev
,
umode_t
*
mode
)
262
{
263
struct
miscdevice
*c =
dev_get_drvdata
(dev);
264
265
if
(mode && c->
mode
)
266
*mode = c->
mode
;
267
if
(c->
nodename
)
268
return
kstrdup
(c->
nodename
,
GFP_KERNEL
);
269
return
NULL
;
270
}
271
272
static
int
__init
misc_init(
void
)
273
{
274
int
err
;
275
276
#ifdef CONFIG_PROC_FS
277
proc_create(
"misc"
, 0,
NULL
, &misc_proc_fops);
278
#endif
279
misc_class =
class_create
(
THIS_MODULE
,
"misc"
);
280
err = PTR_ERR(misc_class);
281
if
(IS_ERR(misc_class))
282
goto
fail_remove;
283
284
err = -
EIO
;
285
if
(register_chrdev(
MISC_MAJOR
,
"misc"
,&misc_fops))
286
goto
fail_printk;
287
misc_class->
devnode
= misc_devnode;
288
return
0;
289
290
fail_printk:
291
printk
(
"unable to get major %d for misc devices\n"
,
MISC_MAJOR
);
292
class_destroy
(misc_class);
293
fail_remove:
294
remove_proc_entry
(
"misc"
,
NULL
);
295
return
err
;
296
}
297
subsys_initcall
(misc_init);
Generated on Thu Jan 10 2013 12:49:00 for Linux Kernel by
1.8.2