OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [misc.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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%q106fm.uucp@wupost.wustl.edu) (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 <pjb27@cam.ac.uk>
17
 *
18
 * Fixed a failing symbol register to free the device registration
19
 *              Alan Cox <alan@lxorguk.ukuu.org.uk> 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 <jack@solucorp.qc.ca>,
27
 *  adapted by Bjorn Ekwall <bj0rn@blox.se>
28
 *  corrected by Alan Cox <alan@lxorguk.ukuu.org.uk>
29
 *
30
 * Changes for kmod (from kerneld):
31
 *      Cyrus Durgin <cider@speakeasy.org>
32
 *
33
 * Added devfs support. Richard Gooch <rgooch@atnf.csiro.au>  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/slab.h>
44
#include <linux/mutex.h>
45
#include <linux/proc_fs.h>
46
#include <linux/seq_file.h>
47
#include <linux/stat.h>
48
#include <linux/init.h>
49
#include <linux/device.h>
50
#include <linux/tty.h>
51
#include <linux/kmod.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 unsigned char misc_minors[DYNAMIC_MINORS / 8];
64
 
65
extern int pmu_device_init(void);
66
 
67
#ifdef CONFIG_PROC_FS
68
static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
69
{
70
        mutex_lock(&misc_mtx);
71
        return seq_list_start(&misc_list, *pos);
72
}
73
 
74
static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
75
{
76
        return seq_list_next(v, &misc_list, pos);
77
}
78
 
79
static void misc_seq_stop(struct seq_file *seq, void *v)
80
{
81
        mutex_unlock(&misc_mtx);
82
}
83
 
84
static int misc_seq_show(struct seq_file *seq, void *v)
85
{
86
        const struct miscdevice *p = list_entry(v, struct miscdevice, list);
87
 
88
        seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : "");
89
        return 0;
90
}
91
 
92
 
93
static struct seq_operations misc_seq_ops = {
94
        .start = misc_seq_start,
95
        .next  = misc_seq_next,
96
        .stop  = misc_seq_stop,
97
        .show  = misc_seq_show,
98
};
99
 
100
static int misc_seq_open(struct inode *inode, struct file *file)
101
{
102
        return seq_open(file, &misc_seq_ops);
103
}
104
 
105
static const struct file_operations misc_proc_fops = {
106
        .owner   = THIS_MODULE,
107
        .open    = misc_seq_open,
108
        .read    = seq_read,
109
        .llseek  = seq_lseek,
110
        .release = seq_release,
111
};
112
#endif
113
 
114
static int misc_open(struct inode * inode, struct file * file)
115
{
116
        int minor = iminor(inode);
117
        struct miscdevice *c;
118
        int err = -ENODEV;
119
        const struct file_operations *old_fops, *new_fops = NULL;
120
 
121
        mutex_lock(&misc_mtx);
122
 
123
        list_for_each_entry(c, &misc_list, list) {
124
                if (c->minor == minor) {
125
                        new_fops = fops_get(c->fops);
126
                        break;
127
                }
128
        }
129
 
130
        if (!new_fops) {
131
                mutex_unlock(&misc_mtx);
132
                request_module("char-major-%d-%d", MISC_MAJOR, minor);
133
                mutex_lock(&misc_mtx);
134
 
135
                list_for_each_entry(c, &misc_list, list) {
136
                        if (c->minor == minor) {
137
                                new_fops = fops_get(c->fops);
138
                                break;
139
                        }
140
                }
141
                if (!new_fops)
142
                        goto fail;
143
        }
144
 
145
        err = 0;
146
        old_fops = file->f_op;
147
        file->f_op = new_fops;
148
        if (file->f_op->open) {
149
                err=file->f_op->open(inode,file);
150
                if (err) {
151
                        fops_put(file->f_op);
152
                        file->f_op = fops_get(old_fops);
153
                }
154
        }
155
        fops_put(old_fops);
156
fail:
157
        mutex_unlock(&misc_mtx);
158
        return err;
159
}
160
 
161
static struct class *misc_class;
162
 
163
static const struct file_operations misc_fops = {
164
        .owner          = THIS_MODULE,
165
        .open           = misc_open,
166
};
167
 
168
 
169
/**
170
 *      misc_register   -       register a miscellaneous device
171
 *      @misc: device structure
172
 *
173
 *      Register a miscellaneous device with the kernel. If the minor
174
 *      number is set to %MISC_DYNAMIC_MINOR a minor number is assigned
175
 *      and placed in the minor field of the structure. For other cases
176
 *      the minor number requested is used.
177
 *
178
 *      The structure passed is linked into the kernel and may not be
179
 *      destroyed until it has been unregistered.
180
 *
181
 *      A zero is returned on success and a negative errno code for
182
 *      failure.
183
 */
184
 
185
int misc_register(struct miscdevice * misc)
186
{
187
        struct miscdevice *c;
188
        dev_t dev;
189
        int err = 0;
190
 
191
        INIT_LIST_HEAD(&misc->list);
192
 
193
        mutex_lock(&misc_mtx);
194
        list_for_each_entry(c, &misc_list, list) {
195
                if (c->minor == misc->minor) {
196
                        mutex_unlock(&misc_mtx);
197
                        return -EBUSY;
198
                }
199
        }
200
 
201
        if (misc->minor == MISC_DYNAMIC_MINOR) {
202
                int i = DYNAMIC_MINORS;
203
                while (--i >= 0)
204
                        if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
205
                                break;
206
                if (i<0) {
207
                        mutex_unlock(&misc_mtx);
208
                        return -EBUSY;
209
                }
210
                misc->minor = i;
211
        }
212
 
213
        if (misc->minor < DYNAMIC_MINORS)
214
                misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
215
        dev = MKDEV(MISC_MAJOR, misc->minor);
216
 
217
        misc->this_device = device_create(misc_class, misc->parent, dev,
218
                                          "%s", misc->name);
219
        if (IS_ERR(misc->this_device)) {
220
                err = PTR_ERR(misc->this_device);
221
                goto out;
222
        }
223
 
224
        /*
225
         * Add it to the front, so that later devices can "override"
226
         * earlier defaults
227
         */
228
        list_add(&misc->list, &misc_list);
229
 out:
230
        mutex_unlock(&misc_mtx);
231
        return err;
232
}
233
 
234
/**
235
 *      misc_deregister - unregister a miscellaneous device
236
 *      @misc: device to unregister
237
 *
238
 *      Unregister a miscellaneous device that was previously
239
 *      successfully registered with misc_register(). Success
240
 *      is indicated by a zero return, a negative errno code
241
 *      indicates an error.
242
 */
243
 
244
int misc_deregister(struct miscdevice * misc)
245
{
246
        int i = misc->minor;
247
 
248
        if (list_empty(&misc->list))
249
                return -EINVAL;
250
 
251
        mutex_lock(&misc_mtx);
252
        list_del(&misc->list);
253
        device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
254
        if (i < DYNAMIC_MINORS && i>0) {
255
                misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
256
        }
257
        mutex_unlock(&misc_mtx);
258
        return 0;
259
}
260
 
261
EXPORT_SYMBOL(misc_register);
262
EXPORT_SYMBOL(misc_deregister);
263
 
264
static int __init misc_init(void)
265
{
266
#ifdef CONFIG_PROC_FS
267
        struct proc_dir_entry *ent;
268
 
269
        ent = create_proc_entry("misc", 0, NULL);
270
        if (ent)
271
                ent->proc_fops = &misc_proc_fops;
272
#endif
273
        misc_class = class_create(THIS_MODULE, "misc");
274
        if (IS_ERR(misc_class))
275
                return PTR_ERR(misc_class);
276
 
277
        if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
278
                printk("unable to get major %d for misc devices\n",
279
                       MISC_MAJOR);
280
                class_destroy(misc_class);
281
                return -EIO;
282
        }
283
        return 0;
284
}
285
subsys_initcall(misc_init);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.