File: /usr/src/linux/drivers/sgi/char/streamable.c

1     /* $Id: streamable.c,v 1.10 2000/02/05 06:47:30 ralf Exp $
2      *
3      * streamable.c: streamable devices. /dev/gfx
4      * (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
5      *
6      * Major 10 is the streams clone device.  The IRIX Xsgi server just
7      * opens /dev/gfx and closes it inmediately.
8      *
9      */
10     
11     #include <linux/fs.h>
12     #include <linux/miscdevice.h>
13     #include <linux/sched.h>
14     #include <linux/kbd_kern.h>
15     #include <linux/vt_kern.h>
16     #include <linux/smp_lock.h>
17     #include <asm/uaccess.h>
18     #include <asm/shmiq.h>
19     #include <asm/keyboard.h>
20     #include "graphics.h"
21     
22     
23     extern struct kbd_struct kbd_table [MAX_NR_CONSOLES];
24     
25     /* console number where forwarding is enabled */
26     int forward_chars;
27     
28     /* To which shmiq this keyboard is assigned */
29     int kbd_assigned_device;
30     
31     /* previous kbd_mode for the forward_chars terminal */
32     int kbd_prev_mode;
33     
34     /* Fetchs the strioctl information from user space for I_STR ioctls */
35     int
36     get_sioc (struct strioctl *sioc, unsigned long arg)
37     {
38     	int v;
39     	
40     	v = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct strioctl));
41     	if (v)
42     		return v;
43     	if (copy_from_user (sioc, (void *) arg, sizeof (struct strioctl)))
44     		return -EFAULT;
45     		
46     	v = verify_area (VERIFY_WRITE, (void *) sioc->ic_dp, sioc->ic_len);
47     	if (v)
48     		return v;
49     	return 0;
50     }
51     
52     /* /dev/gfx device */
53     static int
54     sgi_gfx_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
55     {
56     	printk ("GFX: ioctl 0x%x %ld called\n", cmd, arg);
57     	return 0;
58     	return -EINVAL;
59     }
60     
61     struct file_operations sgi_gfx_fops = {
62     	ioctl:		sgi_gfx_ioctl,
63     };
64      
65     static struct miscdevice dev_gfx = {
66     	SGI_GFX_MINOR, "sgi-gfx", &sgi_gfx_fops
67     };
68     
69     /* /dev/input/keyboard streams device */
70     static idevDesc sgi_kbd_desc = {
71             "keyboard",             /* devName */
72             "KEYBOARD",             /* devType */
73             240,                    /* nButtons */
74             0,                      /* nValuators */
75             0,                      /* nLEDs */
76             0,                      /* nStrDpys */
77             0,                      /* nIntDpys */
78             0,                      /* nBells */
79     	IDEV_HAS_KEYMAP | IDEV_HAS_PCKBD
80     };
81     
82     static int
83     sgi_kbd_sioc (idevInfo *dinfo, int cmd, int size, char *data, int *found)
84     {
85     	*found = 1;
86     	
87     	switch (cmd){
88     
89     	case IDEVINITDEVICE:
90     		return 0;
91     			
92     	case IDEVGETDEVICEDESC:
93     		if (size >= sizeof (idevDesc)){
94     			if (copy_to_user (data, &sgi_kbd_desc, sizeof (sgi_kbd_desc)))
95     				return -EFAULT;
96     			return 0;
97     		}
98     		return -EINVAL;
99     
100     	case IDEVGETKEYMAPDESC:
101     		if (size >= sizeof (idevKeymapDesc)){
102     			if (copy_to_user (data, "US", 3))
103     				return -EFAULT;
104     			return 0;
105     		}
106     		return -EINVAL;
107     	}
108     	*found = 0;
109     	return -EINVAL;
110     }
111     
112     static int
113     sgi_keyb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
114     {
115     	struct strioctl sioc;
116     	int    f, v;
117     	
118     	/* IRIX calls I_PUSH on the opened device, go figure */
119     	if (cmd == I_PUSH)
120     		return 0;
121     
122     	if (cmd == I_STR){
123     		v = get_sioc (&sioc, arg);
124     		if (v)
125     			return v;
126     
127     		/* Why like this?  Because this is a sample piece of code
128     		 * that can be copied into other drivers and shows how to
129     		 * call a stock IRIX xxx_wioctl routine
130     		 *
131     		 * The NULL is supposed to be a idevInfo, right now we
132     		 * do not support this in our kernel.  
133     		 */
134     		return sgi_kbd_sioc (NULL, sioc.ic_cmd, sioc.ic_len, sioc.ic_dp, &f);
135     	}
136     	
137     	if (cmd == SHMIQ_ON){
138     		kbd_assigned_device = arg;
139     		forward_chars = fg_console + 1;
140     		kbd_prev_mode = kbd_table [fg_console].kbdmode;
141     		
142     	        kbd_table [fg_console].kbdmode = VC_RAW;
143     	} else if (cmd == SHMIQ_OFF && forward_chars){
144     		kbd_table [forward_chars-1].kbdmode = kbd_prev_mode;
145     		forward_chars = 0;
146     	} else
147     		return -EINVAL;
148     	return 0;
149     }
150     
151     void
152     kbd_forward_char (int ch)
153     {
154     	static struct shmqevent ev;
155     
156     	ev.data.flags  = (ch & 0200) ? 0 : 1;
157     	ev.data.which  = ch;
158     	ev.data.device = kbd_assigned_device + 0x11;
159     	shmiq_push_event (&ev);
160     }
161     
162     static int
163     sgi_keyb_open (struct inode *inode, struct file *file)
164     {
165     	/* Nothing, but required by the misc driver */
166     	return 0;
167     }
168     
169     struct file_operations sgi_keyb_fops = {
170     	ioctl:		sgi_keyb_ioctl,
171     	open:		sgi_keyb_open,
172     };
173     
174     static struct miscdevice dev_input_keyboard = {
175     	SGI_STREAMS_KEYBOARD, "streams-keyboard", &sgi_keyb_fops
176     };
177     
178     /* /dev/input/mouse streams device */
179     #define MOUSE_VALUATORS 2
180     static idevDesc sgi_mouse_desc = {
181             "mouse",                /* devName */
182             "MOUSE",                /* devType */
183             3,                      /* nButtons */
184             MOUSE_VALUATORS,	/* nValuators */
185             0,                      /* nLEDs */
186             0,                      /* nStrDpys */
187             0,                      /* nIntDpys */
188             0,                      /* nBells */
189     	0			/* flags */
190     };
191     
192     static idevValuatorDesc mouse_default_valuator = {
193     	200,			/* hwMinRes */
194             200,			/* hwMaxRes */
195             0,			/* hwMinVal */
196             65000,			/* hwMaxVal */
197             IDEV_EITHER,		/* possibleModes */
198             IDEV_ABSOLUTE,		/* default mode */
199             200,			/* resolution */
200             0,			/* minVal */
201             65000			/* maxVal */
202     };
203     
204     static int mouse_opened;
205     static idevValuatorDesc mouse_valuators [MOUSE_VALUATORS];
206     	
207     int
208     sgi_mouse_open (struct inode *inode, struct file *file)
209     {
210     	int i;
211     	
212     	if (mouse_opened)
213     		return -EBUSY;
214     	
215     	mouse_opened = 1;
216     	for (i = 0; i < MOUSE_VALUATORS; i++)
217     		mouse_valuators [i] = mouse_default_valuator;
218     	return 0;
219     }
220     
221     static int
222     sgi_mouse_close (struct inode *inode, struct file *filp)
223     {
224     	lock_kernel();
225     	mouse_opened = 0;
226     	unlock_kernel();
227     	return 0;
228     }
229     
230     static int
231     sgi_mouse_sioc (idevInfo *dinfo, int cmd, int size, char *data, int *found)
232     {
233     	*found = 1;
234     
235     	switch (cmd){
236     	case IDEVINITDEVICE:
237     		return 0;
238     			
239     	case IDEVGETDEVICEDESC:
240     		if (size >= sizeof (idevDesc)){
241     			if (copy_to_user (data, &sgi_mouse_desc, sizeof (sgi_mouse_desc)))
242     				return -EFAULT;
243     			return 0;
244     		}
245     		return -EINVAL;
246     
247     	case IDEVGETVALUATORDESC: {
248     		idevGetSetValDesc request, *ureq = (idevGetSetValDesc *) data;
249     		
250     		if (size < sizeof (idevGetSetValDesc))
251     			return -EINVAL;
252     
253     		if (copy_from_user (&request, data, sizeof (request)))
254     			return -EFAULT;
255     		if (request.valNum >= MOUSE_VALUATORS)
256     			return -EINVAL;
257     		if (copy_to_user ((void *)&ureq->desc, 
258     				  (void *)&mouse_valuators [request.valNum],
259     				  sizeof (idevValuatorDesc)))
260     			return -EFAULT;
261     		return 0;
262     	}
263     	}
264     	*found = 0;
265     	return -EINVAL;
266     }
267     
268     static int
269     sgi_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
270     {
271     	struct strioctl sioc;
272     	int    f, v;
273     
274     	/* IRIX calls I_PUSH on the opened device, go figure */
275     	switch (cmd){
276     	case I_PUSH:
277     		return 0;
278     
279     	case I_STR:
280     		v = get_sioc (&sioc, arg);
281     		if (v)
282     			return v;
283     		
284     		/* Why like this?  Because this is a sample piece of code
285     		 * that can be copied into other drivers and shows how to
286     		 * call a stock IRIX xxx_wioctl routine
287     		 *
288     		 * The NULL is supposed to be a idevInfo, right now we
289     		 * do not support this in our kernel.  
290     		 */
291     		return sgi_mouse_sioc (NULL, sioc.ic_cmd, sioc.ic_len, sioc.ic_dp, &f);
292     		
293     	case SHMIQ_ON:
294     	case SHMIQ_OFF:
295     		return 0;
296     	}
297     	return 0;
298     }
299     
300     struct file_operations sgi_mouse_fops = {
301     	ioctl:		sgi_mouse_ioctl,
302     	open:		sgi_mouse_open,
303     	release:	sgi_mouse_close,
304     };
305     
306     /* /dev/input/mouse */
307     static struct miscdevice dev_input_mouse = {
308     	SGI_STREAMS_KEYBOARD, "streams-mouse", &sgi_mouse_fops
309     };
310     
311     void
312     streamable_init (void)
313     {
314     	printk ("streamable misc devices registered (keyb:%d, gfx:%d)\n",
315     		SGI_STREAMS_KEYBOARD, SGI_GFX_MINOR);
316     	
317     	misc_register (&dev_gfx);
318     	misc_register (&dev_input_keyboard);
319     	misc_register (&dev_input_mouse);
320     }
321