OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [hvc_console.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
3
 * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18
 */
19
 
20
#include <linux/init.h>
21
#include <linux/module.h>
22
#include <linux/console.h>
23
#include <linux/major.h>
24
#include <linux/kernel.h>
25
#include <linux/sysrq.h>
26
#include <linux/tty.h>
27
#include <linux/tty_flip.h>
28
#include <linux/sched.h>
29
#include <linux/kbd_kern.h>
30
#include <asm/uaccess.h>
31
#include <linux/spinlock.h>
32
 
33
extern int hvc_count(int *);
34
extern int hvc_get_chars(int index, char *buf, int count);
35
extern int hvc_put_chars(int index, const char *buf, int count);
36
 
37
#define HVC_MAJOR       229
38
#define HVC_MINOR       0
39
 
40
#define MAX_NR_HVC_CONSOLES     4
41
 
42
#define TIMEOUT         ((HZ + 99) / 100)
43
 
44
struct tty_driver hvc_driver;
45
static int hvc_refcount;
46
static struct tty_struct *hvc_table[MAX_NR_HVC_CONSOLES];
47
static struct termios *hvc_termios[MAX_NR_HVC_CONSOLES];
48
static struct termios *hvc_termios_locked[MAX_NR_HVC_CONSOLES];
49
static int hvc_offset;
50
#ifdef CONFIG_MAGIC_SYSRQ
51
static int sysrq_pressed;
52
#endif
53
 
54
#define N_OUTBUF        16
55
 
56
#define __ALIGNED__     __attribute__((__aligned__(8)))
57
 
58
struct hvc_struct {
59
        spinlock_t lock;
60
        int index;
61
        struct tty_struct *tty;
62
        unsigned int count;
63
        int do_wakeup;
64
        char outbuf[N_OUTBUF] __ALIGNED__;
65
        int n_outbuf;
66
};
67
 
68
struct hvc_struct hvc_struct[MAX_NR_HVC_CONSOLES];
69
 
70
static int hvc_open(struct tty_struct *tty, struct file * filp)
71
{
72
        int line = MINOR(tty->device) - tty->driver.minor_start;
73
        struct hvc_struct *hp;
74
        unsigned long flags;
75
 
76
        if (line < 0 || line >= MAX_NR_HVC_CONSOLES)
77
                return -ENODEV;
78
        hp = &hvc_struct[line];
79
 
80
        tty->driver_data = hp;
81
        spin_lock_irqsave(&hp->lock, flags);
82
        hp->tty = tty;
83
        hp->count++;
84
        spin_unlock_irqrestore(&hp->lock, flags);
85
 
86
        return 0;
87
}
88
 
89
static void hvc_close(struct tty_struct *tty, struct file * filp)
90
{
91
        struct hvc_struct *hp = tty->driver_data;
92
        unsigned long flags;
93
 
94
        if (tty_hung_up_p(filp))
95
                return;
96
        spin_lock_irqsave(&hp->lock, flags);
97
        if (--hp->count == 0)
98
                hp->tty = NULL;
99
        else if (hp->count < 0)
100
                printk(KERN_ERR "hvc_close %lu: oops, count is %d\n",
101
                       hp - hvc_struct, hp->count);
102
        spin_unlock_irqrestore(&hp->lock, flags);
103
}
104
 
105
static void hvc_hangup(struct tty_struct *tty)
106
{
107
        struct hvc_struct *hp = tty->driver_data;
108
 
109
        hp->count = 0;
110
        hp->tty = NULL;
111
}
112
 
113
/* called with hp->lock held */
114
static void hvc_push(struct hvc_struct *hp)
115
{
116
        int n;
117
 
118
        n = hvc_put_chars(hp->index + hvc_offset, hp->outbuf, hp->n_outbuf);
119
        if (n <= 0) {
120
                if (n == 0)
121
                        return;
122
                /* throw away output on error; this happens when
123
                   there is no session connected to the vterm. */
124
                hp->n_outbuf = 0;
125
        } else
126
                hp->n_outbuf -= n;
127
        if (hp->n_outbuf > 0)
128
                memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf);
129
        else
130
                hp->do_wakeup = 1;
131
}
132
 
133
static int hvc_write(struct tty_struct *tty, int from_user,
134
                     const unsigned char *buf, int count)
135
{
136
        struct hvc_struct *hp = tty->driver_data;
137
        char *p;
138
        int todo, written = 0;
139
        unsigned long flags;
140
 
141
        spin_lock_irqsave(&hp->lock, flags);
142
        while (count > 0 && (todo = N_OUTBUF - hp->n_outbuf) > 0) {
143
                if (todo > count)
144
                        todo = count;
145
                p = hp->outbuf + hp->n_outbuf;
146
                if (from_user) {
147
                        todo -= copy_from_user(p, buf, todo);
148
                        if (todo == 0) {
149
                                if (written == 0)
150
                                        written = -EFAULT;
151
                                break;
152
                        }
153
                } else
154
                        memcpy(p, buf, todo);
155
                count -= todo;
156
                buf += todo;
157
                hp->n_outbuf += todo;
158
                written += todo;
159
                hvc_push(hp);
160
        }
161
        spin_unlock_irqrestore(&hp->lock, flags);
162
 
163
        return written;
164
}
165
 
166
static int hvc_write_room(struct tty_struct *tty)
167
{
168
        struct hvc_struct *hp = tty->driver_data;
169
 
170
        return N_OUTBUF - hp->n_outbuf;
171
}
172
 
173
static int hvc_chars_in_buffer(struct tty_struct *tty)
174
{
175
        struct hvc_struct *hp = tty->driver_data;
176
 
177
        return hp->n_outbuf;
178
}
179
 
180
static void hvc_poll(int index)
181
{
182
        struct hvc_struct *hp = &hvc_struct[index];
183
        struct tty_struct *tty;
184
        int i, n;
185
        char buf[16] __ALIGNED__;
186
        unsigned long flags;
187
 
188
        spin_lock_irqsave(&hp->lock, flags);
189
 
190
        if (hp->n_outbuf > 0)
191
                hvc_push(hp);
192
 
193
        tty = hp->tty;
194
        if (tty) {
195
                for (;;) {
196
                        if (TTY_FLIPBUF_SIZE - tty->flip.count < sizeof(buf))
197
                                break;
198
                        n = hvc_get_chars(index + hvc_offset, buf, sizeof(buf));
199
                        if (n <= 0)
200
                                break;
201
                        for (i = 0; i < n; ++i) {
202
#ifdef CONFIG_MAGIC_SYSRQ               /* Handle the SysRq Hack */
203
                                if (buf[i] == '\x0f') { /* ^O -- should support a sequence */
204
                                        sysrq_pressed = 1;
205
                                        continue;
206
                                } else if (sysrq_pressed) {
207
                                        handle_sysrq(buf[i], NULL, NULL, tty);
208
                                        sysrq_pressed = 0;
209
                                        continue;
210
                                }
211
#endif
212
                                tty_insert_flip_char(tty, buf[i], 0);
213
                        }
214
                }
215
                if (tty->flip.count)
216
                        tty_schedule_flip(tty);
217
 
218
                if (hp->do_wakeup) {
219
                        hp->do_wakeup = 0;
220
                        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
221
                            && tty->ldisc.write_wakeup)
222
                                (tty->ldisc.write_wakeup)(tty);
223
                        wake_up_interruptible(&tty->write_wait);
224
                }
225
        }
226
 
227
        spin_unlock_irqrestore(&hp->lock, flags);
228
}
229
 
230
int khvcd(void *unused)
231
{
232
        int i;
233
 
234
        daemonize();
235
        reparent_to_init();
236
        strcpy(current->comm, "khvcd");
237
        sigfillset(&current->blocked);
238
 
239
        for (;;) {
240
                for (i = 0; i < MAX_NR_HVC_CONSOLES; ++i)
241
                        hvc_poll(i);
242
                set_current_state(TASK_INTERRUPTIBLE);
243
                schedule_timeout(TIMEOUT);
244
        }
245
}
246
 
247
int __init hvc_init(void)
248
{
249
        int i;
250
 
251
        memset(&hvc_driver, 0, sizeof(struct tty_driver));
252
 
253
        hvc_driver.magic = TTY_DRIVER_MAGIC;
254
        hvc_driver.driver_name = "hvc";
255
#ifdef CONFIG_DEVFS_FS
256
        hvc_driver.name = "hvc/%d";
257
#else
258
        hvc_driver.name = "hvc";
259
#endif
260
        hvc_driver.major = HVC_MAJOR;
261
        hvc_driver.minor_start = HVC_MINOR;
262
        hvc_driver.num = hvc_count(&hvc_offset);
263
        if (hvc_driver.num > MAX_NR_HVC_CONSOLES)
264
                hvc_driver.num = MAX_NR_HVC_CONSOLES;
265
        hvc_driver.type = TTY_DRIVER_TYPE_SYSTEM;
266
        hvc_driver.init_termios = tty_std_termios;
267
        hvc_driver.flags = TTY_DRIVER_REAL_RAW;
268
        hvc_driver.refcount = &hvc_refcount;
269
        hvc_driver.table = hvc_table;
270
        hvc_driver.termios = hvc_termios;
271
        hvc_driver.termios_locked = hvc_termios_locked;
272
 
273
        hvc_driver.open = hvc_open;
274
        hvc_driver.close = hvc_close;
275
        hvc_driver.write = hvc_write;
276
        hvc_driver.hangup = hvc_hangup;
277
        hvc_driver.write_room = hvc_write_room;
278
        hvc_driver.chars_in_buffer = hvc_chars_in_buffer;
279
 
280
        for (i = 0; i < hvc_driver.num; i++) {
281
                hvc_struct[i].lock = SPIN_LOCK_UNLOCKED;
282
                hvc_struct[i].index = i;
283
                tty_register_devfs(&hvc_driver, 0, hvc_driver.minor_start + i);
284
        }
285
 
286
        if (tty_register_driver(&hvc_driver))
287
                panic("Couldn't register hvc console driver\n");
288
 
289
        if (hvc_driver.num > 0)
290
                kernel_thread(khvcd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
291
 
292
        return 0;
293
}
294
 
295
static void __exit hvc_exit(void)
296
{
297
}
298
 
299
void hvc_console_print(struct console *co, const char *b, unsigned count)
300
{
301
        char c[16] __ALIGNED__;
302
        unsigned i, n;
303
        int r, donecr = 0;
304
 
305
        i = n = 0;
306
        while (count > 0 || i > 0) {
307
                if (count > 0 && i < sizeof(c)) {
308
                        if (b[n] == '\n' && !donecr) {
309
                                c[i++] = '\r';
310
                                donecr = 1;
311
                        } else {
312
                                c[i++] = b[n++];
313
                                donecr = 0;
314
                                --count;
315
                        }
316
                } else {
317
                        r = hvc_put_chars(co->index + hvc_offset, c, i);
318
                        if (r < 0) {
319
                                /* throw away chars on error */
320
                                i = 0;
321
                        } else if (r > 0) {
322
                                i -= r;
323
                                if (i > 0)
324
                                        memmove(c, c+r, i);
325
                        }
326
                }
327
        }
328
}
329
 
330
static kdev_t hvc_console_device(struct console *c)
331
{
332
        return MKDEV(HVC_MAJOR, HVC_MINOR + c->index);
333
}
334
 
335
int hvc_wait_for_keypress(struct console *co)
336
{
337
        char c[16] __ALIGNED__;
338
 
339
        while (hvc_get_chars(co->index, &c[0], 1) < 1)
340
                ;
341
        return 0;
342
}
343
 
344
static int __init hvc_console_setup(struct console *co, char *options)
345
{
346
        if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES
347
            || co->index >= hvc_count(&hvc_offset))
348
                return -1;
349
        return 0;
350
}
351
 
352
struct console hvc_con_driver = {
353
        name:           "hvc",
354
        write:          hvc_console_print,
355
        device:         hvc_console_device,
356
        setup:          hvc_console_setup,
357
        flags:          CON_PRINTBUFFER,
358
        index:          -1,
359
};
360
 
361
int __init hvc_console_init(void)
362
{
363
        register_console(&hvc_con_driver);
364
        return 0;
365
}
366
 
367
module_init(hvc_init);
368
module_exit(hvc_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.