import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / char / joystick / serport.c
1 /*
2  * $Id: serport.c,v 1.1.1.1 2005/04/11 02:50:21 jack Exp $
3  *
4  *  Copyright (c) 1999-2001 Vojtech Pavlik
5  *
6  *  Sponsored by SuSE
7  */
8
9 /*
10  * This is a module that converts a tty line into a much simpler
11  * 'serial io port' abstraction that the input device drivers use.
12  */
13
14 /*
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or 
18  * (at your option) any later version.
19  * 
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  * 
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28  * 
29  *  Should you need to contact me, the author, you can do so either by
30  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
31  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
32  */
33
34 #include <asm/uaccess.h>
35 #include <linux/kernel.h>
36 #include <linux/slab.h>
37 #include <linux/module.h>
38 #include <linux/init.h>
39 #include <linux/serio.h>
40 #include <linux/tty.h>
41
42 struct serport {
43         struct tty_struct *tty;
44         wait_queue_head_t wait;
45         struct serio serio;
46 };
47
48 /*
49  * Callback functions from the serio code.
50  */
51
52 static int serport_serio_write(struct serio *serio, unsigned char data)
53 {
54         struct serport *serport = serio->driver;
55         return -(serport->tty->driver.write(serport->tty, 0, &data, 1) != 1);
56 }
57
58 static int serport_serio_open(struct serio *serio)
59 {
60         return 0;
61 }
62
63 static void serport_serio_close(struct serio *serio)
64 {
65         struct serport *serport = serio->driver;
66         wake_up_interruptible(&serport->wait);
67 }
68
69 /*
70  * serport_ldisc_open() is the routine that is called upon setting our line
71  * discipline on a tty. It looks for the Mag, and if found, registers
72  * it as a joystick device.
73  */
74
75 static int serport_ldisc_open(struct tty_struct *tty)
76 {
77         struct serport *serport;
78
79         MOD_INC_USE_COUNT;
80
81         if (!(serport = kmalloc(sizeof(struct serport), GFP_KERNEL))) {
82                 MOD_DEC_USE_COUNT;
83                 return -ENOMEM;
84         }
85
86         memset(serport, 0, sizeof(struct serport));
87
88         serport->tty = tty;
89         tty->disc_data = serport;
90
91         serport->serio.type = SERIO_RS232;
92         serport->serio.write = serport_serio_write;
93         serport->serio.open = serport_serio_open;
94         serport->serio.close = serport_serio_close;
95         serport->serio.driver = serport;
96
97         init_waitqueue_head(&serport->wait);
98
99         return 0;
100 }
101
102 /*
103  * serport_ldisc_close() is the opposite of serport_ldisc_open()
104  */
105
106 static void serport_ldisc_close(struct tty_struct *tty)
107 {
108         struct serport *serport = (struct serport*) tty->disc_data;
109         kfree(serport);
110         MOD_DEC_USE_COUNT;
111 }
112
113 /*
114  * serport_ldisc_receive() is called by the low level tty driver when characters
115  * are ready for us. We forward the characters, one by one to the 'interrupt'
116  * routine.
117  */
118
119 static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
120 {
121         struct serport *serport = (struct serport*) tty->disc_data;
122         int i;
123         for (i = 0; i < count; i++)
124                 if (serport->serio.dev)
125                         serport->serio.dev->interrupt(&serport->serio, cp[i], 0);
126 }
127
128 /*
129  * serport_ldisc_room() reports how much room we do have for receiving data.
130  * Although we in fact have infinite room, we need to specify some value
131  * here, and 256 seems to be reasonable.
132  */
133
134 static int serport_ldisc_room(struct tty_struct *tty)
135 {
136         return 256;
137 }
138
139 /*
140  * serport_ldisc_read() just waits indefinitely if everything goes well. 
141  * However, when the serio driver closes the serio port, it finishes,
142  * returning 0 characters.
143  */
144
145 static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char * buf, size_t nr)
146 {
147         struct serport *serport = (struct serport*) tty->disc_data;
148         DECLARE_WAITQUEUE(wait, current);
149         char name[32];
150
151 #ifdef CONFIG_DEVFS_FS
152         sprintf(name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
153 #else
154         sprintf(name, "%s%d", tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
155 #endif
156
157         serio_register_port(&serport->serio);
158
159         printk(KERN_INFO "serio%d: Serial port %s\n", serport->serio.number, name);
160
161         add_wait_queue(&serport->wait, &wait);
162         current->state = TASK_INTERRUPTIBLE;
163
164         while(serport->serio.type && !signal_pending(current)) schedule();
165
166         current->state = TASK_RUNNING;
167         remove_wait_queue(&serport->wait, &wait);
168
169         serio_unregister_port(&serport->serio);
170
171         return 0;
172 }
173
174 /*
175  * serport_ldisc_ioctl() allows to set the port protocol, and device ID
176  */
177
178 static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
179 {
180         struct serport *serport = (struct serport*) tty->disc_data;
181         
182         switch (cmd) {
183                 case SPIOCSTYPE:
184                         return get_user(serport->serio.type, (unsigned long *) arg);
185         }
186
187         return -EINVAL;
188 }
189
190 /*
191  * The line discipline structure.
192  */
193
194 static struct tty_ldisc serport_ldisc = {
195         name:           "input",
196         open:           serport_ldisc_open,
197         close:          serport_ldisc_close,
198         read:           serport_ldisc_read,
199         ioctl:          serport_ldisc_ioctl,
200         receive_buf:    serport_ldisc_receive,
201         receive_room:   serport_ldisc_room,
202 };
203
204 /*
205  * The functions for insering/removing us as a module.
206  */
207
208 int __init serport_init(void)
209 {
210         if (tty_register_ldisc(N_MOUSE, &serport_ldisc)) {
211                 printk(KERN_ERR "serport.c: Error registering line discipline.\n");
212                 return -ENODEV;
213         }
214
215         return  0;
216 }
217
218 void __exit serport_exit(void)
219 {
220         tty_register_ldisc(N_MOUSE, NULL);
221 }
222
223 module_init(serport_init);
224 module_exit(serport_exit);
225
226 MODULE_LICENSE("GPL");