5 * \author Rickard E. (Rik) Faith <faith@valinux.com>
9 * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org
11 * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California.
12 * All Rights Reserved.
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
21 * The above copyright notice and this permission notice (including the next
22 * paragraph) shall be included in all copies or substantial portions of the
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 * DEALINGS IN THE SOFTWARE.
36 #define DRM_STUB_MAXCARDS 16 /* Enough for one machine */
38 static struct class_simple *drm_class;
40 /** Stub list. One for each minor. */
41 static struct drm_stub_list {
43 struct file_operations *fops; /**< file operations */
44 struct proc_dir_entry *dev_root; /**< proc directory entry */
47 static struct proc_dir_entry *DRM(stub_root);
49 /** Stub information */
50 static struct drm_stub_info {
51 int (*info_register)(const char *name, struct file_operations *fops,
53 int (*info_unregister)(int minor);
57 * File \c open operation.
59 * \param inode device inode.
60 * \param filp file pointer.
62 * Puts the drm_stub_list::fops corresponding to the device minor number into
63 * \p filp, call the \c open method, and restore the file operations.
65 static int DRM(stub_open)(struct inode *inode, struct file *filp)
67 int minor = iminor(inode);
69 struct file_operations *old_fops;
71 if (!DRM(stub_list) || !DRM(stub_list)[minor].fops) return -ENODEV;
72 old_fops = filp->f_op;
73 filp->f_op = fops_get(DRM(stub_list)[minor].fops);
74 if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) {
76 filp->f_op = fops_get(old_fops);
83 /** File operations structure */
84 static struct file_operations DRM(stub_fops) = {
86 .open = DRM(stub_open)
90 * Get a device minor number.
92 * \param name driver name.
93 * \param fops file operations.
94 * \param dev DRM device.
95 * \return minor number on success, or a negative number on failure.
97 * Allocate and initialize ::stub_list if one doesn't exist already. Search an
98 * empty entry and initialize it to the given parameters, and create the proc
99 * init entry via proc_init().
101 static int DRM(stub_getminor)(const char *name, struct file_operations *fops,
106 if (!DRM(stub_list)) {
107 DRM(stub_list) = DRM(alloc)(sizeof(*DRM(stub_list))
108 * DRM_STUB_MAXCARDS, DRM_MEM_STUB);
109 if(!DRM(stub_list)) return -1;
110 for (i = 0; i < DRM_STUB_MAXCARDS; i++) {
111 DRM(stub_list)[i].name = NULL;
112 DRM(stub_list)[i].fops = NULL;
115 for (i = 0; i < DRM_STUB_MAXCARDS; i++) {
116 if (!DRM(stub_list)[i].fops) {
117 DRM(stub_list)[i].name = name;
118 DRM(stub_list)[i].fops = fops;
119 DRM(stub_root) = DRM(proc_init)(dev, i, DRM(stub_root),
122 class_simple_device_add(drm_class, MKDEV(DRM_MAJOR, i), NULL, name);
130 * Put a device minor number.
132 * \param minor minor number.
133 * \return always zero.
135 * Cleans up the proc resources. If a minor is zero then release the foreign
136 * "drm" data, otherwise unregisters the "drm" data, frees the stub list and
137 * unregisters the character device.
139 static int DRM(stub_putminor)(int minor)
141 if (minor < 0 || minor >= DRM_STUB_MAXCARDS) return -1;
142 DRM(stub_list)[minor].name = NULL;
143 DRM(stub_list)[minor].fops = NULL;
144 DRM(proc_cleanup)(minor, DRM(stub_root),
145 DRM(stub_list)[minor].dev_root);
147 class_simple_device_remove(MKDEV(DRM_MAJOR, minor));
148 inter_module_put("drm");
150 inter_module_unregister("drm");
151 DRM(free)(DRM(stub_list),
152 sizeof(*DRM(stub_list)) * DRM_STUB_MAXCARDS,
154 unregister_chrdev(DRM_MAJOR, "drm");
155 class_simple_device_remove(MKDEV(DRM_MAJOR, minor));
156 class_simple_destroy(drm_class);
164 * \param name driver name.
165 * \param fops file operations
166 * \param dev DRM device.
167 * \return zero on success or a negative number on failure.
169 * Attempt to register the char device and get the foreign "drm" data. If
170 * successful then another module already registered so gets the stub info,
171 * otherwise use this module stub info and make it available for other modules.
173 * Finally calls stub_info::info_register.
175 int DRM(stub_register)(const char *name, struct file_operations *fops,
178 struct drm_stub_info *i = NULL;
183 ret1 = register_chrdev(DRM_MAJOR, "drm", &DRM(stub_fops));
185 drm_class = class_simple_create(THIS_MODULE, "drm");
186 if (IS_ERR(drm_class)) {
187 printk (KERN_ERR "Error creating drm class.\n");
188 unregister_chrdev(DRM_MAJOR, "drm");
189 return PTR_ERR(drm_class);
192 else if (ret1 == -EBUSY)
193 i = (struct drm_stub_info *)inter_module_get("drm");
198 /* Already registered */
199 DRM(stub_info).info_register = i->info_register;
200 DRM(stub_info).info_unregister = i->info_unregister;
201 DRM_DEBUG("already registered\n");
202 } else if (DRM(stub_info).info_register != DRM(stub_getminor)) {
203 DRM(stub_info).info_register = DRM(stub_getminor);
204 DRM(stub_info).info_unregister = DRM(stub_putminor);
205 DRM_DEBUG("calling inter_module_register\n");
206 inter_module_register("drm", THIS_MODULE, &DRM(stub_info));
208 if (DRM(stub_info).info_register) {
209 ret2 = DRM(stub_info).info_register(name, fops, dev);
212 unregister_chrdev(DRM_MAJOR, "drm");
213 class_simple_destroy(drm_class);
216 inter_module_unregister("drm");
228 * Calls drm_stub_info::unregister.
230 int DRM(stub_unregister)(int minor)
232 DRM_DEBUG("%d\n", minor);
233 if (DRM(stub_info).info_unregister)
234 return DRM(stub_info).info_unregister(minor);