2 * shmiq.c: shared memory input queue driver
3 * written 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
5 * We implement /dev/shmiq, /dev/qcntlN here
6 * this is different from IRIX that has shmiq as a misc
7 * streams device and the and qcntl devices as a major device.
9 * minor number 0 implements /dev/shmiq,
10 * any other number implements /dev/qcntl${minor-1}
12 * /dev/shmiq is used by the X server for two things:
14 * 1. for I_LINK()ing trough ioctl the file handle of a
17 * 2. To send STREAMS-commands to the devices with the
18 * QIO ioctl interface.
20 * I have not yet figured how to make multiple X servers share
21 * /dev/shmiq for having different servers running. So, for now
22 * I keep a kernel-global array of inodes that are pushed into
25 * /dev/qcntlN is used by the X server for two things:
27 * 1. Issuing the QIOCATTACH for mapping the shared input
28 * queue into the address space of the X server (yeah, yeah,
29 * I did not invent this interface).
31 * 2. used by select. I bet it is used for checking for events on
34 * Now the problem is that there does not seem anything that
35 * establishes a connection between /dev/shmiq and the qcntlN file. I
36 * need an strace from an X server that runs on a machine with more
37 * than one keyboard. And this is a problem since the file handles
38 * are pushed in /dev/shmiq, while the events should be dispatched to
39 * the /dev/qcntlN device.
41 * Until then, I just allow for 1 qcntl device.
46 #include <linux/miscdevice.h>
47 #include <linux/sched.h>
48 #include <linux/file.h>
49 #include <linux/interrupt.h>
50 #include <linux/vmalloc.h>
51 #include <linux/wait.h>
52 #include <linux/major.h>
53 #include <linux/smp_lock.h>
55 #include <asm/shmiq.h>
57 #include <asm/uaccess.h>
61 /* we are not really getting any more than a few files in the shmiq */
62 #define MAX_SHMIQ_DEVS 10
65 * One per X server running, not going to get very big.
66 * Even if we have this we now assume just 1 /dev/qcntl can be
67 * active, I need to find how this works on multi-headed machines.
69 #define MAX_SHMI_QUEUES 4
74 struct shmiqsetcpos cpos
;
75 } shmiq_pushed_devices
[MAX_SHMIQ_DEVS
];
77 /* /dev/qcntlN attached memory regions, location and size of the event queue */
79 int opened
; /* if this device has been opened */
80 void *shmiq_vaddr
; /* mapping in kernel-land */
81 int tail
; /* our copy of the shmiq->tail */
85 struct wait_queue
*proc_list
;
86 struct fasync_struct
*fasync
;
87 } shmiqs
[MAX_SHMI_QUEUES
];
90 shmiq_push_event (struct shmqevent
*e
)
92 struct sharedMemoryInputQueue
*s
;
93 int device
= 0; /* FIXME: here is the assumption /dev/shmiq == /dev/qcntl0 */
96 if (!shmiqs
[device
].mapped
)
98 s
= shmiqs
[device
].shmiq_vaddr
;
101 if (s
->tail
!= shmiqs
[device
].tail
){
102 s
->flags
|= SHMIQ_CORRUPTED
;
105 tail_next
= (s
->tail
+ 1) % (shmiqs
[device
].events
);
107 if (tail_next
== s
->head
){
108 s
->flags
|= SHMIQ_OVERFLOW
;
112 e
->un
.time
= jiffies
;
113 s
->events
[s
->tail
] = *e
;
114 printk ("KERNEL: dev=%d which=%d type=%d flags=%d\n",
115 e
->data
.device
, e
->data
.which
, e
->data
.type
, e
->data
.flags
);
117 shmiqs
[device
].tail
= tail_next
;
118 if (shmiqs
[device
].fasync
)
119 kill_fasync (shmiqs
[device
].fasync
, SIGIO
);
120 wake_up_interruptible (&shmiqs
[device
].proc_list
);
124 shmiq_manage_file (struct file
*filp
)
128 if (!filp
->f_op
|| !filp
->f_op
->ioctl
)
131 for (i
= 0; i
< MAX_SHMIQ_DEVS
; i
++){
132 if (shmiq_pushed_devices
[i
].used
)
134 if ((*filp
->f_op
->ioctl
)(filp
->f_dentry
->d_inode
, filp
, SHMIQ_ON
, i
) != 0)
136 shmiq_pushed_devices
[i
].used
= 1;
137 shmiq_pushed_devices
[i
].filp
= filp
;
138 shmiq_pushed_devices
[i
].cpos
.x
= 0;
139 shmiq_pushed_devices
[i
].cpos
.y
= 0;
146 shmiq_forget_file (unsigned long fdes
)
150 if (fdes
> MAX_SHMIQ_DEVS
)
153 if (!shmiq_pushed_devices
[fdes
].used
)
156 filp
= shmiq_pushed_devices
[fdes
].filp
;
158 (*filp
->f_op
->ioctl
)(filp
->f_dentry
->d_inode
, filp
, SHMIQ_OFF
, 0);
159 shmiq_pushed_devices
[fdes
].filp
= 0;
162 shmiq_pushed_devices
[fdes
].used
= 0;
168 shmiq_sioc (int device
, int cmd
, struct strioctl
*s
)
173 * Ok, we just return the index they are providing us
175 printk ("QIOCGETINDX: returning %d\n", *(int *)s
->ic_dp
);
179 struct muxioctl
*mux
= (struct muxioctl
*) s
->ic_dp
;
181 printk ("Double indirect ioctl: [%d, %x\n", mux
->index
, mux
->realcmd
);
186 if (copy_from_user (&shmiq_pushed_devices
[device
].cpos
, s
->ic_dp
,
187 sizeof (struct shmiqsetcpos
)))
192 printk ("Unknown I_STR request for shmiq device: 0x%x\n", cmd
);
197 shmiq_ioctl (struct inode
*inode
, struct file
*f
, unsigned int cmd
, unsigned long arg
)
200 struct strioctl sioc
;
205 * They are giving us the file descriptor for one
206 * of their streams devices
214 v
= shmiq_manage_file (file
);
218 * Remove a device from our list of managed
222 v
= shmiq_forget_file (arg
);
226 v
= get_sioc (&sioc
, arg
);
230 /* FIXME: This forces device = 0 */
231 return shmiq_sioc (0, sioc
.ic_cmd
, &sioc
);
240 extern sys_munmap(unsigned long addr
, size_t len
);
243 qcntl_ioctl (struct inode
*inode
, struct file
*filp
, unsigned int cmd
, unsigned long arg
, int minor
)
246 struct vm_area_struct
*vma
;
251 * The address space is already mapped as a /dev/zero
252 * mapping. FIXME: check that /dev/zero is what the user
253 * had mapped before :-)
259 v
= verify_area (VERIFY_READ
, (void *) arg
, sizeof (struct shmiqreq
));
262 if (copy_from_user (&req
, (void *) arg
, sizeof (req
)))
264 /* Do not allow to attach to another region if it has been already attached */
265 if (shmiqs
[minor
].mapped
){
266 printk ("SHMIQ:The thingie is already mapped\n");
270 vaddr
= (unsigned long) req
.user_vaddr
;
271 vma
= find_vma (current
->mm
, vaddr
);
273 printk ("SHMIQ: could not find %lx the vma\n", vaddr
);
276 s
= req
.arg
* sizeof (struct shmqevent
) + sizeof (struct sharedMemoryInputQueue
);
277 v
= sys_munmap (vaddr
, s
);
278 do_mmap (filp
, vaddr
, s
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
|MAP_FIXED
, 0);
279 shmiqs
[minor
].events
= req
.arg
;
280 shmiqs
[minor
].mapped
= 1;
288 shmiq_nopage (struct vm_area_struct
*vma
, unsigned long address
, int write_access
)
290 /* Do not allow for mremap to expand us */
294 static struct vm_operations_struct qcntl_mmap
= {
295 NULL
, /* no special mmap-open */
296 NULL
, /* no special mmap-close */
297 NULL
, /* no special mmap-unmap */
298 NULL
, /* no special mmap-protect */
299 NULL
, /* no special mmap-sync */
300 NULL
, /* no special mmap-advise */
301 shmiq_nopage
, /* our magic no-page fault handler */
302 NULL
, /* no special mmap-wppage */
303 NULL
, /* no special mmap-swapout */
304 NULL
/* no special mmap-swapin */
308 shmiq_qcntl_mmap (struct file
*file
, struct vm_area_struct
*vma
)
310 int minor
= MINOR (file
->f_dentry
->d_inode
->i_rdev
), error
;
312 unsigned long mem
, start
;
314 /* mmap is only supported on the qcntl devices */
318 if (vma
->vm_offset
!= 0)
321 size
= vma
->vm_end
- vma
->vm_start
;
322 start
= vma
->vm_start
;
323 mem
= (unsigned long) shmiqs
[minor
].shmiq_vaddr
= vmalloc_uncached (size
);
327 /* Prevent the swapper from considering these pages for swap and touching them */
328 vma
->vm_flags
|= (VM_SHM
| VM_LOCKED
| VM_IO
);
329 vma
->vm_ops
= &qcntl_mmap
;
331 /* Uncache the pages */
332 vma
->vm_page_prot
= PAGE_USERIO
;
334 error
= vmap_page_range (vma
->vm_start
, size
, mem
);
336 shmiqs
[minor
].tail
= 0;
337 /* Init the shared memory input queue */
338 memset (shmiqs
[minor
].shmiq_vaddr
, 0, size
);
344 shmiq_qcntl_ioctl (struct inode
*inode
, struct file
*filp
, unsigned int cmd
, unsigned long arg
)
346 int minor
= MINOR (inode
->i_rdev
);
351 return shmiq_ioctl (inode
, filp
, cmd
, arg
);
353 return qcntl_ioctl (inode
, filp
, cmd
, arg
, minor
);
357 shmiq_qcntl_poll (struct file
*filp
, poll_table
*wait
)
359 struct sharedMemoryInputQueue
*s
;
360 int minor
= MINOR (filp
->f_dentry
->d_inode
->i_rdev
);
365 if (!shmiqs
[minor
].mapped
)
368 poll_wait (filp
, &shmiqs
[minor
].proc_list
, wait
);
369 s
= shmiqs
[minor
].shmiq_vaddr
;
370 if (s
->head
!= s
->tail
)
371 return POLLIN
| POLLRDNORM
;
376 shmiq_qcntl_open (struct inode
*inode
, struct file
*filp
)
378 int minor
= MINOR (inode
->i_rdev
);
384 if (minor
> MAX_SHMI_QUEUES
)
386 if (shmiqs
[minor
].opened
)
390 shmiqs
[minor
].opened
= 1;
391 shmiqs
[minor
].shmiq_vaddr
= 0;
397 shmiq_qcntl_fasync (struct file
*file
, int on
)
400 int minor
= MINOR (file
->f_dentry
->d_inode
->i_rdev
);
402 retval
= fasync_helper (file
, on
, &shmiqs
[minor
].fasync
);
409 shmiq_qcntl_close (struct inode
*inode
, struct file
*filp
)
411 int minor
= MINOR (inode
->i_rdev
);
415 for (j
= 0; j
< MAX_SHMIQ_DEVS
; j
++)
416 shmiq_forget_file (j
);
419 if (minor
> MAX_SHMI_QUEUES
)
421 if (shmiqs
[minor
].opened
== 0)
425 shmiq_qcntl_fasync (filp
, 0);
426 shmiqs
[minor
].opened
= 0;
427 shmiqs
[minor
].mapped
= 0;
428 shmiqs
[minor
].events
= 0;
429 shmiqs
[minor
].fasync
= 0;
430 vfree (shmiqs
[minor
].shmiq_vaddr
);
431 shmiqs
[minor
].shmiq_vaddr
= 0;
438 file_operations shmiq_fops
=
444 shmiq_qcntl_poll
, /* poll */
445 shmiq_qcntl_ioctl
, /* ioctl */
446 shmiq_qcntl_mmap
, /* mmap */
447 shmiq_qcntl_open
, /* open */
449 shmiq_qcntl_close
, /* close */
451 shmiq_qcntl_fasync
, /* fasync */
452 NULL
, /* check_media_change */
453 NULL
, /* revalidate */
459 printk ("SHMIQ setup\n");
460 register_chrdev (SHMIQ_MAJOR
, "shmiq", &shmiq_fops
);