File: /usr/src/linux/drivers/sgi/char/usema.c
1 /*
2 * usema.c: software semaphore driver (see IRIX's usema(7M))
3 * written 1997 Mike Shaver (shaver@neon.ingenia.ca)
4 * 1997 Miguel de Icaza (miguel@kernel.org)
5 *
6 * This file contains the implementation of /dev/usemaclone,
7 * the devices used by IRIX's us* semaphore routines.
8 *
9 * /dev/usemaclone is used to create a new semaphore device, and then
10 * the semaphore is manipulated via ioctls.
11 *
12 * At least for the zero-contention case, lock set and unset as well
13 * as semaphore P and V are done in userland, which makes things a
14 * little bit better. I suspect that the ioctls are used to register
15 * the process as blocking, etc.
16 *
17 * Much inspiration and structure stolen from Miguel's shmiq work.
18 *
19 * For more information:
20 * usema(7m), usinit(3p), usnewsema(3p)
21 * /usr/include/sys/usioctl.h
22 *
23 */
24 #include <linux/fs.h>
25 #include <linux/miscdevice.h>
26 #include <linux/sched.h>
27 #include <linux/file.h>
28 #include <linux/major.h>
29 #include <linux/poll.h>
30 #include <linux/string.h>
31 #include <linux/dcache.h>
32 #include <linux/mm.h>
33 #include <linux/module.h>
34 #include <linux/slab.h>
35 #include <linux/smp_lock.h>
36 #include "usema.h"
37
38 #include <asm/usioctl.h>
39 #include <asm/mman.h>
40 #include <asm/uaccess.h>
41
42 struct irix_usema {
43 struct file *filp;
44 wait_queue_head_t proc_list;
45 };
46
47
48 static int
49 sgi_usema_attach (usattach_t * attach, struct irix_usema *usema)
50 {
51 int newfd;
52 newfd = get_unused_fd();
53 if (newfd < 0)
54 return newfd;
55
56 get_file(usema->filp);
57 fd_install(newfd, usema->filp);
58 /* Is that it? */
59 printk("UIOCATTACHSEMA: new usema fd is %d", newfd);
60 return newfd;
61 }
62
63 static int
64 sgi_usemaclone_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
65 unsigned long arg)
66 {
67 struct irix_usema *usema = file->private_data;
68 int retval;
69
70 printk("[%s:%d] wants ioctl 0x%xd (arg 0x%lx)",
71 current->comm, current->pid, cmd, arg);
72
73 switch(cmd) {
74 case UIOCATTACHSEMA: {
75 /* They pass us information about the semaphore to
76 which they wish to be attached, and we create&return
77 a new fd corresponding to the appropriate semaphore.
78 */
79 usattach_t *attach = (usattach_t *)arg;
80 retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
81 if (retval) {
82 printk("[%s:%d] sgi_usema_ioctl(UIOCATTACHSEMA): "
83 "verify_area failure",
84 current->comm, current->pid);
85 return retval;
86 }
87 if (usema == 0)
88 return -EINVAL;
89
90 printk("UIOCATTACHSEMA: attaching usema %p to process %d\n",
91 usema, current->pid);
92 /* XXX what is attach->us_handle for? */
93 return sgi_usema_attach(attach, usema);
94 break;
95 }
96 case UIOCABLOCK: /* XXX make `async' */
97 case UIOCNOIBLOCK: /* XXX maybe? */
98 case UIOCBLOCK: {
99 /* Block this process on the semaphore */
100 usattach_t *attach = (usattach_t *)arg;
101
102 retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
103 if (retval) {
104 printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): "
105 "verify_area failure",
106 current->comm, current->pid);
107 return retval;
108 }
109 printk("UIOC*BLOCK: putting process %d to sleep on usema %p",
110 current->pid, usema);
111 if (cmd == UIOCNOIBLOCK)
112 interruptible_sleep_on(&usema->proc_list);
113 else
114 sleep_on(&usema->proc_list);
115 return 0;
116 }
117 case UIOCAUNBLOCK: /* XXX make `async' */
118 case UIOCUNBLOCK: {
119 /* Wake up all process waiting on this semaphore */
120 usattach_t *attach = (usattach_t *)arg;
121
122 retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
123 if (retval) {
124 printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): "
125 "verify_area failure",
126 current->comm, current->pid);
127 return retval;
128 }
129
130 printk("[%s:%d] releasing usema %p",
131 current->comm, current->pid, usema);
132 wake_up(&usema->proc_list);
133 return 0;
134 }
135 }
136 return -ENOSYS;
137 }
138
139 static unsigned int
140 sgi_usemaclone_poll(struct file *filp, poll_table *wait)
141 {
142 struct irix_usema *usema = filp->private_data;
143
144 printk("[%s:%d] wants to poll usema %p",
145 current->comm, current->pid, usema);
146
147 return 0;
148 }
149
150 static int
151 sgi_usemaclone_open(struct inode *inode, struct file *filp)
152 {
153 struct irix_usema *usema;
154
155 usema = kmalloc (sizeof (struct irix_usema), GFP_KERNEL);
156 if (!usema)
157 return -ENOMEM;
158
159 usema->filp = filp;
160 init_waitqueue_head(&usema->proc_list);
161 filp->private_data = usema;
162
163 return 0;
164 }
165
166 struct file_operations sgi_usemaclone_fops = {
167 poll: sgi_usemaclone_poll,
168 ioctl: sgi_usemaclone_ioctl,
169 open: sgi_usemaclone_open,
170 };
171
172 static struct miscdevice dev_usemaclone = {
173 SGI_USEMACLONE, "usemaclone", &sgi_usemaclone_fops
174 };
175
176 void
177 usema_init(void)
178 {
179 printk("usemaclone misc device registered (minor: %d)\n",
180 SGI_USEMACLONE);
181 misc_register(&dev_usemaclone);
182 }
183
184 EXPORT_SYMBOL(usema_init);
185