Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
494 giacomo 1
/*
2
 * Input device TTY line discipline
3
 *
4
 * Copyright (c) 1999-2002 Vojtech Pavlik
5
 *
6
 * This is a module that converts a tty line into a much simpler
7
 * 'serial io port' abstraction that the input device drivers use.
8
 */
9
 
10
/*
11
 * This program is free software; you can redistribute it and/or modify it
12
 * under the terms of the GNU General Public License version 2 as published by
13
 * the Free Software Foundation.
14
 */
15
 
16
#include <linuxcomp.h>
17
 
18
#include <asm/uaccess.h>
19
#include <linux/kernel.h>
20
#include <linux/slab.h>
21
#include <linux/module.h>
22
#include <linux/init.h>
23
#include <linux/serio.h>
24
#include <linux/tty.h>
25
 
26
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
27
MODULE_DESCRIPTION("Input device TTY line discipline");
28
MODULE_LICENSE("GPL");
29
MODULE_ALIAS_LDISC(N_MOUSE);
30
 
31
#define SERPORT_BUSY    1
32
 
33
struct serport {
34
        struct tty_struct *tty;
35
        wait_queue_head_t wait;
36
        struct serio serio;
37
        unsigned long flags;
38
        char phys[32];
39
};
40
 
41
char serport_name[] = "Serial port";
42
 
43
/*
44
 * Callback functions from the serio code.
45
 */
46
 
47
static int serport_serio_write(struct serio *serio, unsigned char data)
48
{
49
        struct serport *serport = serio->driver;
50
        return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1);
51
}
52
 
53
static int serport_serio_open(struct serio *serio)
54
{
55
        return 0;
56
}
57
 
58
static void serport_serio_close(struct serio *serio)
59
{
60
        struct serport *serport = serio->driver;
61
 
62
        serport->serio.type = 0;
63
        wake_up_interruptible(&serport->wait);
64
}
65
 
66
/*
67
 * serport_ldisc_open() is the routine that is called upon setting our line
68
 * discipline on a tty. It prepares the serio struct.
69
 */
70
 
71
static int serport_ldisc_open(struct tty_struct *tty)
72
{
73
        struct serport *serport;
74
        char name[64];
75
 
76
        serport = kmalloc(sizeof(struct serport), GFP_KERNEL);
77
        if (unlikely(!serport))
78
                return -ENOMEM;
79
        memset(serport, 0, sizeof(struct serport));
80
 
81
        set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
82
        serport->tty = tty;
83
        tty->disc_data = serport;
84
 
85
        snprintf26(serport->phys, sizeof(serport->phys), "%s/serio0", tty_name(tty, name));
86
 
87
        serport->serio.name = serport_name;
88
        serport->serio.phys = serport->phys;
89
 
90
        serport->serio.type = SERIO_RS232;
91
        serport->serio.write = serport_serio_write;
92
        serport->serio.open = serport_serio_open;
93
        serport->serio.close = serport_serio_close;
94
        serport->serio.driver = serport;
95
 
96
        init_waitqueue_head(&serport->wait);
97
 
98
        return 0;
99
}
100
 
101
/*
102
 * serport_ldisc_close() is the opposite of serport_ldisc_open()
103
 */
104
 
105
static void serport_ldisc_close(struct tty_struct *tty)
106
{
107
        struct serport *serport = (struct serport*) tty->disc_data;
108
        kfree(serport);
109
}
110
 
111
/*
112
 * serport_ldisc_receive() is called by the low level tty driver when characters
113
 * are ready for us. We forward the characters, one by one to the 'interrupt'
114
 * routine.
115
 *
116
 * FIXME: We should get pt_regs from the tty layer and forward them to
117
 *        serio_interrupt here.
118
 */
119
 
120
static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
121
{
122
        struct serport *serport = (struct serport*) tty->disc_data;
123
        int i;
124
        for (i = 0; i < count; i++)
125
                serio_interrupt(&serport->serio, cp[i], 0, NULL);
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
        char name[64];
149
 
150
        if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
151
                return -EBUSY;
152
 
153
        serio_register_port(&serport->serio);
154
        printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name));
155
        wait_event_interruptible(serport->wait, !serport->serio.type);
156
        serio_unregister_port(&serport->serio);
157
 
158
        clear_bit(SERPORT_BUSY, &serport->flags);
159
 
160
        return 0;
161
}
162
 
163
/*
164
 * serport_ldisc_ioctl() allows to set the port protocol, and device ID
165
 */
166
 
167
static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
168
{
169
        struct serport *serport = (struct serport*) tty->disc_data;
170
 
171
        if (cmd == SPIOCSTYPE)
172
                return get_user(serport->serio.type, (unsigned long *) arg);
173
 
174
        return -EINVAL;
175
}
176
 
177
static void serport_ldisc_write_wakeup(struct tty_struct * tty)
178
{
179
        struct serport *sp = (struct serport *) tty->disc_data;
180
 
181
        serio_dev_write_wakeup(&sp->serio);
182
}
183
 
184
/*
185
 * The line discipline structure.
186
 */
187
 
188
static struct tty_ldisc serport_ldisc = {
189
        .owner =        THIS_MODULE,
190
        .name =         "input",
191
        .open =         serport_ldisc_open,
192
        .close =        serport_ldisc_close,
193
        .read =         serport_ldisc_read,
194
        .ioctl =        serport_ldisc_ioctl,
195
        .receive_buf =  serport_ldisc_receive,
196
        .receive_room = serport_ldisc_room,
197
        .write_wakeup = serport_ldisc_write_wakeup
198
};
199
 
200
/*
201
 * The functions for insering/removing us as a module.
202
 */
203
 
204
/*static*/ int __init serport_init(void)
205
{
206
        int retval;
207
        retval = tty_register_ldisc(N_MOUSE, &serport_ldisc);
208
        if (retval)
209
                printk(KERN_ERR "serport.c: Error registering line discipline.\n");
210
 
211
        return  retval;
212
}
213
 
214
/*static*/ void __exit serport_exit(void)
215
{
216
        tty_register_ldisc(N_MOUSE, NULL);
217
}
218
 
219
module_init(serport_init);
220
module_exit(serport_exit);