summaryrefslogtreecommitdiffstats
path: root/fs/devfs/util.c
blob: 6e3f2f7827001a09ff514c6fb14391a36b125767 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*  devfs (Device FileSystem) utilities.

    Copyright (C) 1999-2000  Richard Gooch

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
    The postal address is:
      Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.

    ChangeLog

    19991031   Richard Gooch <rgooch@atnf.csiro.au>
               Created.
    19991103   Richard Gooch <rgooch@atnf.csiro.au>
               Created <_devfs_convert_name> and supported SCSI and IDE CD-ROMs
    20000203   Richard Gooch <rgooch@atnf.csiro.au>
               Changed operations pointer type to void *.
    20000621   Richard Gooch <rgooch@atnf.csiro.au>
               Changed interface to <devfs_register_series>.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/locks.h>
#include <linux/kdev_t.h>
#include <linux/devfs_fs_kernel.h>


/*  Private functions follow  */

/**
 *	_devfs_convert_name - Convert from an old style location-based name to new style.
 *	@new: The new name will be written here.
 *	@old: The old name.
 *	@disc: If true, disc partitioning information should be processed.
 */

static void __init _devfs_convert_name (char *new, const char *old, int disc)
{
    int host, bus, target, lun;
    char *ptr;
    char part[8];

    /*  Decode "c#b#t#u#"  */
    if (old[0] != 'c') return;
    host = simple_strtol (old + 1, &ptr, 10);
    if (ptr[0] != 'b') return;
    bus = simple_strtol (ptr + 1, &ptr, 10);
    if (ptr[0] != 't') return;
    target = simple_strtol (ptr + 1, &ptr, 10);
    if (ptr[0] != 'u') return;
    lun = simple_strtol (ptr + 1, &ptr, 10);
    if (disc)
    {
	/*  Decode "p#"  */
	if (ptr[0] == 'p') sprintf (part, "part%s", ptr + 1);
	else strcpy (part, "disc");
    }
    else part[0] = '\0';
    sprintf (new, "/host%d/bus%d/target%d/lun%d/%s",
	     host, bus, target, lun, part);
}   /*  End Function _devfs_convert_name  */


/*  Public functions follow  */

/**
 *	devfs_make_root - Create the root FS device entry if required.
 *	@name: The name of the root FS device, as passed by "root=".
 */

void __init devfs_make_root (const char *name)
{
    char dest[64];

    if ( (strncmp (name, "sd/", 3) == 0) || (strncmp (name, "sr/", 3) == 0) )
    {
	strcpy (dest, "../scsi");
	_devfs_convert_name (dest + 7, name + 3, (name[1] == 'd') ? 1 : 0);
    }
    else if ( (strncmp (name, "ide/hd/", 7) == 0) ||
	      (strncmp (name, "ide/cd/", 7) == 0) )
    {
	strcpy (dest, "..");
	_devfs_convert_name (dest + 2, name + 7, (name[4] == 'h') ? 1 : 0);
    }
    else return;
    devfs_mk_symlink (NULL, name, 0, DEVFS_FL_DEFAULT, dest, 0, NULL,NULL);
}   /*  End Function devfs_make_root  */


/**
 *	devfs_register_tape - Register a tape device in the "/dev/tapes" hierarchy.
 *	@de: Any tape device entry in the device directory.
 */

void devfs_register_tape (devfs_handle_t de)
{
    int pos;
    devfs_handle_t parent, slave;
    char name[16], dest[64];
    static unsigned int tape_counter = 0;
    static devfs_handle_t tape_dir = NULL;

    if (tape_dir == NULL) tape_dir = devfs_mk_dir (NULL, "tapes", 5, NULL);
    parent = devfs_get_parent (de);
    pos = devfs_generate_path (parent, dest + 3, sizeof dest - 3);
    if (pos < 0) return;
    strncpy (dest + pos, "../", 3);
    sprintf (name, "tape%u", tape_counter++);
    devfs_mk_symlink (tape_dir, name, 0, DEVFS_FL_DEFAULT, dest + pos, 0,
		      &slave, NULL);
    devfs_auto_unregister (de, slave);
}   /*  End Function devfs_register_tape  */
EXPORT_SYMBOL(devfs_register_tape);


/**
 *	devfs_register_series - Register a sequence of device entries.
 *	@dir: The handle to the parent devfs directory entry. If this is %NULL the
 *		new names are relative to the root of the devfs.
 *	@format: The printf-style format string. A single "\%u" is allowed.
 *	@flags: A set of bitwise-ORed flags (DEVFS_FL_*).
 *	@major: The major number. Not needed for regular files.
 *	@minor_start: The starting minor number. Not needed for regular files.
 *	@mode: The default file mode.
 *	@ops: The &file_operations or &block_device_operations structure.
 *		This must not be externally deallocated.
 *	@info: An arbitrary pointer which will be written to the private_data
 *		field of the &file structure passed to the device driver. You can set
 *		this to whatever you like, and change it once the file is opened (the next
 *		file opened will not see this change).
 */

void devfs_register_series (devfs_handle_t dir, const char *format,
			    unsigned int num_entries, unsigned int flags,
			    unsigned int major, unsigned int minor_start,
			    umode_t mode, void *ops, void *info)
{
    unsigned int count;
    char devname[128];

    for (count = 0; count < num_entries; ++count)
    {
	sprintf (devname, format, count);
	devfs_register (dir, devname, flags, major, minor_start + count,
			mode, ops, info);
    }
}   /*  End Function devfs_register_series  */
EXPORT_SYMBOL(devfs_register_series);