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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [devfs/] [util.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*  devfs (Device FileSystem) utilities.
2
 
3
    Copyright (C) 1999-2002  Richard Gooch
4
 
5
    This library is free software; you can redistribute it and/or
6
    modify it under the terms of the GNU Library General Public
7
    License as published by the Free Software Foundation; either
8
    version 2 of the License, or (at your option) any later version.
9
 
10
    This library is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
    Library General Public License for more details.
14
 
15
    You should have received a copy of the GNU Library General Public
16
    License along with this library; if not, write to the Free
17
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
 
19
    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
20
    The postal address is:
21
      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
22
 
23
    ChangeLog
24
 
25
    19991031   Richard Gooch <rgooch@atnf.csiro.au>
26
               Created.
27
    19991103   Richard Gooch <rgooch@atnf.csiro.au>
28
               Created <_devfs_convert_name> and supported SCSI and IDE CD-ROMs
29
    20000203   Richard Gooch <rgooch@atnf.csiro.au>
30
               Changed operations pointer type to void *.
31
    20000621   Richard Gooch <rgooch@atnf.csiro.au>
32
               Changed interface to <devfs_register_series>.
33
    20000622   Richard Gooch <rgooch@atnf.csiro.au>
34
               Took account of interface change to <devfs_mk_symlink>.
35
               Took account of interface change to <devfs_mk_dir>.
36
    20010519   Richard Gooch <rgooch@atnf.csiro.au>
37
               Documentation cleanup.
38
    20010709   Richard Gooch <rgooch@atnf.csiro.au>
39
               Created <devfs_*alloc_major> and <devfs_*alloc_devnum>.
40
    20010710   Richard Gooch <rgooch@atnf.csiro.au>
41
               Created <devfs_*alloc_unique_number>.
42
    20010730   Richard Gooch <rgooch@atnf.csiro.au>
43
               Documentation typo fix.
44
    20010806   Richard Gooch <rgooch@atnf.csiro.au>
45
               Made <block_semaphore> and <char_semaphore> private.
46
    20010813   Richard Gooch <rgooch@atnf.csiro.au>
47
               Fixed bug in <devfs_alloc_unique_number>: limited to 128 numbers
48
    20010818   Richard Gooch <rgooch@atnf.csiro.au>
49
               Updated major masks up to Linus' "no new majors" proclamation.
50
               Block: were 126 now 122 free, char: were 26 now 19 free.
51
    20020324   Richard Gooch <rgooch@atnf.csiro.au>
52
               Fixed bug in <devfs_alloc_unique_number>: was clearing beyond
53
               bitfield.
54
    20020326   Richard Gooch <rgooch@atnf.csiro.au>
55
               Fixed bitfield data type for <devfs_*alloc_devnum>.
56
               Made major bitfield type and initialiser 64 bit safe.
57
    20020413   Richard Gooch <rgooch@atnf.csiro.au>
58
               Fixed shift warning on 64 bit machines.
59
    20020428   Richard Gooch <rgooch@atnf.csiro.au>
60
               Copied and used macro for error messages from fs/devfs/base.c
61
*/
62
#include <linux/module.h>
63
#include <linux/init.h>
64
#include <linux/devfs_fs_kernel.h>
65
#include <linux/slab.h>
66
#include <linux/vmalloc.h>
67
 
68
#include <asm/bitops.h>
69
 
70
#define PRINTK(format, args...) \
71
   {printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);}
72
 
73
 
74
/*  Private functions follow  */
75
 
76
/**
77
 *      devfs_register_tape - Register a tape device in the "/dev/tapes" hierarchy.
78
 *      @de: Any tape device entry in the device directory.
79
 */
80
 
81
void devfs_register_tape (devfs_handle_t de)
82
{
83
    int pos;
84
    devfs_handle_t parent, slave;
85
    char name[16], dest[64];
86
    static unsigned int tape_counter;
87
    static devfs_handle_t tape_dir;
88
 
89
    if (tape_dir == NULL) tape_dir = devfs_mk_dir (NULL, "tapes", NULL);
90
    parent = devfs_get_parent (de);
91
    pos = devfs_generate_path (parent, dest + 3, sizeof dest - 3);
92
    if (pos < 0) return;
93
    strncpy (dest + pos, "../", 3);
94
    sprintf (name, "tape%u", tape_counter++);
95
    devfs_mk_symlink (tape_dir, name, DEVFS_FL_DEFAULT, dest + pos,
96
                      &slave, NULL);
97
    devfs_auto_unregister (de, slave);
98
}   /*  End Function devfs_register_tape  */
99
EXPORT_SYMBOL(devfs_register_tape);
100
 
101
 
102
/**
103
 *      devfs_register_series - Register a sequence of device entries.
104
 *      @dir: The handle to the parent devfs directory entry. If this is %NULL
105
 *              the new names are relative to the root of the devfs.
106
 *      @format: The printf-style format string. A single "\%u" is allowed.
107
 *      @num_entries: The number of entries to register.
108
 *      @flags: A set of bitwise-ORed flags (DEVFS_FL_*).
109
 *      @major: The major number. Not needed for regular files.
110
 *      @minor_start: The starting minor number. Not needed for regular files.
111
 *      @mode: The default file mode.
112
 *      @ops: The &file_operations or &block_device_operations structure.
113
 *              This must not be externally deallocated.
114
 *      @info: An arbitrary pointer which will be written to the private_data
115
 *              field of the &file structure passed to the device driver. You
116
 *              can set this to whatever you like, and change it once the file
117
 *              is opened (the next file opened will not see this change).
118
 */
119
 
120
void devfs_register_series (devfs_handle_t dir, const char *format,
121
                            unsigned int num_entries, unsigned int flags,
122
                            unsigned int major, unsigned int minor_start,
123
                            umode_t mode, void *ops, void *info)
124
{
125
    unsigned int count;
126
    char devname[128];
127
 
128
    for (count = 0; count < num_entries; ++count)
129
    {
130
        sprintf (devname, format, count);
131
        devfs_register (dir, devname, flags, major, minor_start + count,
132
                        mode, ops, info);
133
    }
134
}   /*  End Function devfs_register_series  */
135
EXPORT_SYMBOL(devfs_register_series);
136
 
137
 
138
struct major_list
139
{
140
    spinlock_t lock;
141
    unsigned long bits[256 / BITS_PER_LONG];
142
};
143
#if BITS_PER_LONG == 32
144
#  define INITIALISER64(low,high) (low), (high)
145
#else
146
#  define INITIALISER64(low,high) ( (unsigned long) (high) << 32 | (low) )
147
#endif
148
 
149
/*  Block majors already assigned:
150
    0-3, 7-9, 11-63, 65-99, 101-113, 120-127, 199, 201, 240-255
151
    Total free: 122
152
*/
153
static struct major_list block_major_list =
154
{SPIN_LOCK_UNLOCKED,
155
    {INITIALISER64 (0xfffffb8f, 0xffffffff),  /*  Majors 0-31,    32-63    */
156
     INITIALISER64 (0xfffffffe, 0xff03ffef),  /*  Majors 64-95,   96-127   */
157
     INITIALISER64 (0x00000000, 0x00000000),  /*  Majors 128-159, 160-191  */
158
     INITIALISER64 (0x00000280, 0xffff0000),  /*  Majors 192-223, 224-255  */
159
    }
160
};
161
 
162
/*  Char majors already assigned:
163
    0-7, 9-151, 154-158, 160-211, 216-221, 224-230, 240-255
164
    Total free: 19
165
*/
166
static struct major_list char_major_list =
167
{SPIN_LOCK_UNLOCKED,
168
    {INITIALISER64 (0xfffffeff, 0xffffffff),  /*  Majors 0-31,    32-63    */
169
     INITIALISER64 (0xffffffff, 0xffffffff),  /*  Majors 64-95,   96-127   */
170
     INITIALISER64 (0x7cffffff, 0xffffffff),  /*  Majors 128-159, 160-191  */
171
     INITIALISER64 (0x3f0fffff, 0xffff007f),  /*  Majors 192-223, 224-255  */
172
    }
173
};
174
 
175
 
176
/**
177
 *      devfs_alloc_major - Allocate a major number.
178
 *      @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK)
179
 
180
 *      Returns the allocated major, else -1 if none are available.
181
 *      This routine is thread safe and does not block.
182
 */
183
 
184
int devfs_alloc_major (char type)
185
{
186
    int major;
187
    struct major_list *list;
188
 
189
    list = (type == DEVFS_SPECIAL_CHR) ? &char_major_list : &block_major_list;
190
    spin_lock (&list->lock);
191
    major = find_first_zero_bit (list->bits, 256);
192
    if (major < 256) __set_bit (major, list->bits);
193
    else major = -1;
194
    spin_unlock (&list->lock);
195
    return major;
196
}   /*  End Function devfs_alloc_major  */
197
EXPORT_SYMBOL(devfs_alloc_major);
198
 
199
 
200
/**
201
 *      devfs_dealloc_major - Deallocate a major number.
202
 *      @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK)
203
 *      @major: The major number.
204
 *      This routine is thread safe and does not block.
205
 */
206
 
207
void devfs_dealloc_major (char type, int major)
208
{
209
    int was_set;
210
    struct major_list *list;
211
 
212
    if (major < 0) return;
213
    list = (type == DEVFS_SPECIAL_CHR) ? &char_major_list : &block_major_list;
214
    spin_lock (&list->lock);
215
    was_set = __test_and_clear_bit (major, list->bits);
216
    spin_unlock (&list->lock);
217
    if (!was_set) PRINTK ("(): major %d was already free\n", major);
218
}   /*  End Function devfs_dealloc_major  */
219
EXPORT_SYMBOL(devfs_dealloc_major);
220
 
221
 
222
struct minor_list
223
{
224
    int major;
225
    unsigned long bits[256 / BITS_PER_LONG];
226
    struct minor_list *next;
227
};
228
 
229
struct device_list
230
{
231
    struct minor_list *first, *last;
232
    int none_free;
233
};
234
 
235
static DECLARE_MUTEX (block_semaphore);
236
static struct device_list block_list;
237
 
238
static DECLARE_MUTEX (char_semaphore);
239
static struct device_list char_list;
240
 
241
 
242
/**
243
 *      devfs_alloc_devnum - Allocate a device number.
244
 *      @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK).
245
 *
246
 *      Returns the allocated device number, else NODEV if none are available.
247
 *      This routine is thread safe and may block.
248
 */
249
 
250
kdev_t devfs_alloc_devnum (char type)
251
{
252
    int minor;
253
    struct semaphore *semaphore;
254
    struct device_list *list;
255
    struct minor_list *entry;
256
 
257
    if (type == DEVFS_SPECIAL_CHR)
258
    {
259
        semaphore = &char_semaphore;
260
        list = &char_list;
261
    }
262
    else
263
    {
264
        semaphore = &block_semaphore;
265
        list = &block_list;
266
    }
267
    if (list->none_free) return NODEV;  /*  Fast test  */
268
    down (semaphore);
269
    if (list->none_free)
270
    {
271
        up (semaphore);
272
        return NODEV;
273
    }
274
    for (entry = list->first; entry != NULL; entry = entry->next)
275
    {
276
        minor = find_first_zero_bit (entry->bits, 256);
277
        if (minor >= 256) continue;
278
        __set_bit (minor, entry->bits);
279
        up (semaphore);
280
        return mk_kdev (entry->major, minor);
281
    }
282
    /*  Need to allocate a new major  */
283
    if ( ( entry = kmalloc (sizeof *entry, GFP_KERNEL) ) == NULL )
284
    {
285
        list->none_free = 1;
286
        up (semaphore);
287
        return NODEV;
288
    }
289
    memset (entry, 0, sizeof *entry);
290
    if ( ( entry->major = devfs_alloc_major (type) ) < 0 )
291
    {
292
        list->none_free = 1;
293
        up (semaphore);
294
        kfree (entry);
295
        return NODEV;
296
    }
297
    __set_bit (0, entry->bits);
298
    if (list->first == NULL) list->first = entry;
299
    else list->last->next = entry;
300
    list->last = entry;
301
    up (semaphore);
302
    return mk_kdev (entry->major, 0);
303
}   /*  End Function devfs_alloc_devnum  */
304
EXPORT_SYMBOL(devfs_alloc_devnum);
305
 
306
 
307
/**
308
 *      devfs_dealloc_devnum - Dellocate a device number.
309
 *      @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK).
310
 *      @devnum: The device number.
311
 *
312
 *      This routine is thread safe and does not block.
313
 */
314
 
315
void devfs_dealloc_devnum (char type, kdev_t devnum)
316
{
317
    int major, minor;
318
    struct semaphore *semaphore;
319
    struct device_list *list;
320
    struct minor_list *entry;
321
 
322
    if ( kdev_none (devnum) ) return;
323
    if (type == DEVFS_SPECIAL_CHR)
324
    {
325
        semaphore = &char_semaphore;
326
        list = &char_list;
327
    }
328
    else
329
    {
330
        semaphore = &block_semaphore;
331
        list = &block_list;
332
    }
333
    major = major (devnum);
334
    minor = minor (devnum);
335
    down (semaphore);
336
    for (entry = list->first; entry != NULL; entry = entry->next)
337
    {
338
        int was_set;
339
 
340
        if (entry->major != major) continue;
341
        was_set = __test_and_clear_bit (minor, entry->bits);
342
        if (was_set) list->none_free = 0;
343
        up (semaphore);
344
        if (!was_set)
345
            PRINTK ( "(): device %s was already free\n", kdevname (devnum) );
346
        return;
347
    }
348
    up (semaphore);
349
    PRINTK ( "(): major for %s not previously allocated\n",
350
             kdevname (devnum) );
351
}   /*  End Function devfs_dealloc_devnum  */
352
EXPORT_SYMBOL(devfs_dealloc_devnum);
353
 
354
 
355
/**
356
 *      devfs_alloc_unique_number - Allocate a unique (positive) number.
357
 *      @space: The number space to allocate from.
358
 *
359
 *      Returns the allocated unique number, else a negative error code.
360
 *      This routine is thread safe and may block.
361
 */
362
 
363
int devfs_alloc_unique_number (struct unique_numspace *space)
364
{
365
    int number;
366
    unsigned int length;
367
 
368
    /*  Get around stupid lack of semaphore initialiser  */
369
    spin_lock (&space->init_lock);
370
    if (!space->sem_initialised)
371
    {
372
        sema_init (&space->semaphore, 1);
373
        space->sem_initialised = 1;
374
    }
375
    spin_unlock (&space->init_lock);
376
    down (&space->semaphore);
377
    if (space->num_free < 1)
378
    {
379
        void *bits;
380
 
381
        if (space->length < 16) length = 16;
382
        else length = space->length << 1;
383
        if ( ( bits = vmalloc (length) ) == NULL )
384
        {
385
            up (&space->semaphore);
386
            return -ENOMEM;
387
        }
388
        if (space->bits != NULL)
389
        {
390
            memcpy (bits, space->bits, space->length);
391
            vfree (space->bits);
392
        }
393
        space->num_free = (length - space->length) << 3;
394
        space->bits = bits;
395
        memset (bits + space->length, 0, length - space->length);
396
        space->length = length;
397
    }
398
    number = find_first_zero_bit (space->bits, space->length << 3);
399
    --space->num_free;
400
    __set_bit (number, space->bits);
401
    up (&space->semaphore);
402
    return number;
403
}   /*  End Function devfs_alloc_unique_number  */
404
EXPORT_SYMBOL(devfs_alloc_unique_number);
405
 
406
 
407
/**
408
 *      devfs_dealloc_unique_number - Deallocate a unique (positive) number.
409
 *      @space: The number space to deallocate from.
410
 *      @number: The number to deallocate.
411
 *
412
 *      This routine is thread safe and may block.
413
 */
414
 
415
void devfs_dealloc_unique_number (struct unique_numspace *space, int number)
416
{
417
    int was_set;
418
 
419
    if (number < 0) return;
420
    down (&space->semaphore);
421
    was_set = __test_and_clear_bit (number, space->bits);
422
    if (was_set) ++space->num_free;
423
    up (&space->semaphore);
424
    if (!was_set) PRINTK ("(): number %d was already free\n", number);
425
}   /*  End Function devfs_dealloc_unique_number  */
426
EXPORT_SYMBOL(devfs_dealloc_unique_number);

powered by: WebSVN 2.1.0

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