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);
|