1 /* $Id: shmiq.c,v 1.12 1999/06/17 13:29:04 ralf Exp $
3 * shmiq.c: shared memory input queue driver
4 * written 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
6 * We implement /dev/shmiq, /dev/qcntlN here
7 * this is different from IRIX that has shmiq as a misc
8 * streams device and the and qcntl devices as a major device.
10 * minor number 0 implements /dev/shmiq,
11 * any other number implements /dev/qcntl${minor-1}
13 * /dev/shmiq is used by the X server for two things:
15 * 1. for I_LINK()ing trough ioctl the file handle of a
18 * 2. To send STREAMS-commands to the devices with the
19 * QIO ioctl interface.
21 * I have not yet figured how to make multiple X servers share
22 * /dev/shmiq for having different servers running. So, for now
23 * I keep a kernel-global array of inodes that are pushed into
26 * /dev/qcntlN is used by the X server for two things:
28 * 1. Issuing the QIOCATTACH for mapping the shared input
29 * queue into the address space of the X server (yeah, yeah,
30 * I did not invent this interface).
32 * 2. used by select. I bet it is used for checking for events on
35 * Now the problem is that there does not seem anything that
36 * establishes a connection between /dev/shmiq and the qcntlN file. I
37 * need an strace from an X server that runs on a machine with more
38 * than one keyboard. And this is a problem since the file handles
39 * are pushed in /dev/shmiq, while the events should be dispatched to
40 * the /dev/qcntlN device.
42 * Until then, I just allow for 1 qcntl device.
47 #include <linux/miscdevice.h>
48 #include <linux/sched.h>
49 #include <linux/file.h>
50 #include <linux/interrupt.h>
51 #include <linux/poll.h>
52 #include <linux/vmalloc.h>
53 #include <linux/wait.h>
54 #include <linux/major.h>
55 #include <linux/smp_lock.h>
57 #include <asm/shmiq.h>
59 #include <asm/uaccess.h>
63 /* we are not really getting any more than a few files in the shmiq */
64 #define MAX_SHMIQ_DEVS 10
67 * One per X server running, not going to get very big.
68 * Even if we have this we now assume just 1 /dev/qcntl can be
69 * active, I need to find how this works on multi-headed machines.
71 #define MAX_SHMI_QUEUES 4
76 struct shmiqsetcpos cpos
;
77 } shmiq_pushed_devices
[MAX_SHMIQ_DEVS
];
79 /* /dev/qcntlN attached memory regions, location and size of the event queue */
81 int opened
; /* if this device has been opened */
82 void *shmiq_vaddr
; /* mapping in kernel-land */
83 int tail
; /* our copy of the shmiq->tail */
87 wait_queue_head_t proc_list
;
88 struct fasync_struct
*fasync
;
89 } shmiqs
[MAX_SHMI_QUEUES
];
92 shmiq_push_event (struct shmqevent
*e
)
94 struct sharedMemoryInputQueue
*s
;
95 int device
= 0; /* FIXME: here is the assumption /dev/shmiq == /dev/qcntl0 */
98 if (!shmiqs
[device
].mapped
)
100 s
= shmiqs
[device
].shmiq_vaddr
;
103 if (s
->tail
!= shmiqs
[device
].tail
){
104 s
->flags
|= SHMIQ_CORRUPTED
;
107 tail_next
= (s
->tail
+ 1) % (shmiqs
[device
].events
);
109 if (tail_next
== s
->head
){
110 s
->flags
|= SHMIQ_OVERFLOW
;
114 e
->un
.time
= jiffies
;
115 s
->events
[s
->tail
] = *e
;
116 printk ("KERNEL: dev=%d which=%d type=%d flags=%d\n",
117 e
->data
.device
, e
->data
.which
, e
->data
.type
, e
->data
.flags
);
119 shmiqs
[device
].tail
= tail_next
;
120 if (shmiqs
[device
].fasync
)
121 kill_fasync (shmiqs
[device
].fasync
, SIGIO
);
122 wake_up_interruptible (&shmiqs
[device
].proc_list
);
126 shmiq_manage_file (struct file
*filp
)
130 if (!filp
->f_op
|| !filp
->f_op
->ioctl
)
133 for (i
= 0; i
< MAX_SHMIQ_DEVS
; i
++){
134 if (shmiq_pushed_devices
[i
].used
)
136 if ((*filp
->f_op
->ioctl
)(filp
->f_dentry
->d_inode
, filp
, SHMIQ_ON
, i
) != 0)
138 shmiq_pushed_devices
[i
].used
= 1;
139 shmiq_pushed_devices
[i
].filp
= filp
;
140 shmiq_pushed_devices
[i
].cpos
.x
= 0;
141 shmiq_pushed_devices
[i
].cpos
.y
= 0;
148 shmiq_forget_file (unsigned long fdes
)
152 if (fdes
> MAX_SHMIQ_DEVS
)
155 if (!shmiq_pushed_devices
[fdes
].used
)
158 filp
= shmiq_pushed_devices
[fdes
].filp
;
160 (*filp
->f_op
->ioctl
)(filp
->f_dentry
->d_inode
, filp
, SHMIQ_OFF
, 0);
161 shmiq_pushed_devices
[fdes
].filp
= 0;
164 shmiq_pushed_devices
[fdes
].used
= 0;
170 shmiq_sioc (int device
, int cmd
, struct strioctl
*s
)
175 * Ok, we just return the index they are providing us
177 printk ("QIOCGETINDX: returning %d\n", *(int *)s
->ic_dp
);
181 struct muxioctl
*mux
= (struct muxioctl
*) s
->ic_dp
;
183 printk ("Double indirect ioctl: [%d, %x\n", mux
->index
, mux
->realcmd
);
188 if (copy_from_user (&shmiq_pushed_devices
[device
].cpos
, s
->ic_dp
,
189 sizeof (struct shmiqsetcpos
)))
194 printk ("Unknown I_STR request for shmiq device: 0x%x\n", cmd
);
199 shmiq_ioctl (struct inode
*inode
, struct file
*f
, unsigned int cmd
, unsigned long arg
)
202 struct strioctl sioc
;
207 * They are giving us the file descriptor for one
208 * of their streams devices
216 v
= shmiq_manage_file (file
);
220 * Remove a device from our list of managed
224 v
= shmiq_forget_file (arg
);
228 v
= get_sioc (&sioc
, arg
);
232 /* FIXME: This forces device = 0 */
233 return shmiq_sioc (0, sioc
.ic_cmd
, &sioc
);
242 extern int sys_munmap(unsigned long addr
, size_t len
);
245 qcntl_ioctl (struct inode
*inode
, struct file
*filp
, unsigned int cmd
, unsigned long arg
, int minor
)
248 struct vm_area_struct
*vma
;
253 * The address space is already mapped as a /dev/zero
254 * mapping. FIXME: check that /dev/zero is what the user
255 * had mapped before :-)
261 v
= verify_area (VERIFY_READ
, (void *) arg
, sizeof (struct shmiqreq
));
264 if (copy_from_user (&req
, (void *) arg
, sizeof (req
)))
266 /* Do not allow to attach to another region if it has been already attached */
267 if (shmiqs
[minor
].mapped
){
268 printk ("SHMIQ:The thingie is already mapped\n");
272 vaddr
= (unsigned long) req
.user_vaddr
;
273 vma
= find_vma (current
->mm
, vaddr
);
275 printk ("SHMIQ: could not find %lx the vma\n", vaddr
);
278 s
= req
.arg
* sizeof (struct shmqevent
) + sizeof (struct sharedMemoryInputQueue
);
279 v
= sys_munmap (vaddr
, s
);
280 do_mmap (filp
, vaddr
, s
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
|MAP_FIXED
, 0);
281 shmiqs
[minor
].events
= req
.arg
;
282 shmiqs
[minor
].mapped
= 1;
290 shmiq_nopage (struct vm_area_struct
*vma
, unsigned long address
, int write_access
)
292 /* Do not allow for mremap to expand us */
296 static struct vm_operations_struct qcntl_mmap
= {
297 NULL
, /* no special mmap-open */
298 NULL
, /* no special mmap-close */
299 NULL
, /* no special mmap-unmap */
300 NULL
, /* no special mmap-protect */
301 NULL
, /* no special mmap-sync */
302 NULL
, /* no special mmap-advise */
303 shmiq_nopage
, /* our magic no-page fault handler */
304 NULL
, /* no special mmap-wppage */
305 NULL
, /* no special mmap-swapout */
306 NULL
/* no special mmap-swapin */
310 shmiq_qcntl_mmap (struct file
*file
, struct vm_area_struct
*vma
)
312 int minor
= MINOR (file
->f_dentry
->d_inode
->i_rdev
), error
;
314 unsigned long mem
, start
;
316 /* mmap is only supported on the qcntl devices */
320 if (vma
->vm_offset
!= 0)
323 size
= vma
->vm_end
- vma
->vm_start
;
324 start
= vma
->vm_start
;
325 mem
= (unsigned long) shmiqs
[minor
].shmiq_vaddr
= vmalloc_uncached (size
);
329 /* Prevent the swapper from considering these pages for swap and touching them */
330 vma
->vm_flags
|= (VM_SHM
| VM_LOCKED
| VM_IO
);
331 vma
->vm_ops
= &qcntl_mmap
;
333 /* Uncache the pages */
334 vma
->vm_page_prot
= PAGE_USERIO
;
336 error
= vmap_page_range (vma
->vm_start
, size
, mem
);
338 shmiqs
[minor
].tail
= 0;
339 /* Init the shared memory input queue */
340 memset (shmiqs
[minor
].shmiq_vaddr
, 0, size
);
346 shmiq_qcntl_ioctl (struct inode
*inode
, struct file
*filp
, unsigned int cmd
, unsigned long arg
)
348 int minor
= MINOR (inode
->i_rdev
);
353 return shmiq_ioctl (inode
, filp
, cmd
, arg
);
355 return qcntl_ioctl (inode
, filp
, cmd
, arg
, minor
);
359 shmiq_qcntl_poll (struct file
*filp
, poll_table
*wait
)
361 struct sharedMemoryInputQueue
*s
;
362 int minor
= MINOR (filp
->f_dentry
->d_inode
->i_rdev
);
367 if (!shmiqs
[minor
].mapped
)
370 poll_wait (filp
, &shmiqs
[minor
].proc_list
, wait
);
371 s
= shmiqs
[minor
].shmiq_vaddr
;
372 if (s
->head
!= s
->tail
)
373 return POLLIN
| POLLRDNORM
;
378 shmiq_qcntl_open (struct inode
*inode
, struct file
*filp
)
380 int minor
= MINOR (inode
->i_rdev
);
386 if (minor
> MAX_SHMI_QUEUES
)
388 if (shmiqs
[minor
].opened
)
392 shmiqs
[minor
].opened
= 1;
393 shmiqs
[minor
].shmiq_vaddr
= 0;
399 shmiq_qcntl_fasync (int fd
, struct file
*file
, int on
)
402 int minor
= MINOR (file
->f_dentry
->d_inode
->i_rdev
);
404 retval
= fasync_helper (fd
, file
, on
, &shmiqs
[minor
].fasync
);
411 shmiq_qcntl_close (struct inode
*inode
, struct file
*filp
)
413 int minor
= MINOR (inode
->i_rdev
);
417 for (j
= 0; j
< MAX_SHMIQ_DEVS
; j
++)
418 shmiq_forget_file (j
);
421 if (minor
> MAX_SHMI_QUEUES
)
423 if (shmiqs
[minor
].opened
== 0)
427 shmiq_qcntl_fasync (-1, filp
, 0);
428 shmiqs
[minor
].opened
= 0;
429 shmiqs
[minor
].mapped
= 0;
430 shmiqs
[minor
].events
= 0;
431 shmiqs
[minor
].fasync
= 0;
432 vfree (shmiqs
[minor
].shmiq_vaddr
);
433 shmiqs
[minor
].shmiq_vaddr
= 0;
440 file_operations shmiq_fops
=
446 shmiq_qcntl_poll
, /* poll */
447 shmiq_qcntl_ioctl
, /* ioctl */
448 shmiq_qcntl_mmap
, /* mmap */
449 shmiq_qcntl_open
, /* open */
451 shmiq_qcntl_close
, /* close */
453 shmiq_qcntl_fasync
, /* fasync */
454 NULL
, /* check_media_change */
455 NULL
, /* revalidate */
461 printk ("SHMIQ setup\n");
462 register_chrdev (SHMIQ_MAJOR
, "shmiq", &shmiq_fops
);