Merge from vendor branch GCC:
[dragonfly.git] / sys / platform / vkernel / platform / console.c
1 /*
2  * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/sys/platform/vkernel/platform/console.c,v 1.8 2007/01/09 07:23:03 dillon Exp $
35  */
36
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/conf.h>
40 #include <sys/cons.h>
41 #include <sys/tty.h>
42 #include <sys/termios.h>
43 #include <sys/fcntl.h>
44 #include <machine/md_var.h>
45 #include <unistd.h>
46 #include <termios.h>
47
48 static int console_stolen_by_kernel;
49 static struct callout console_callout;
50
51 /*
52  * Global console locking functions
53  */
54 void
55 cons_lock(void)
56 {
57 }
58
59 void
60 cons_unlock(void)
61 {
62 }
63
64 /************************************************************************
65  *                          CONSOLE DEVICE                              *
66  ************************************************************************
67  *
68  */
69
70 #define CDEV_MAJOR      183
71
72 static int vcons_tty_param(struct tty *tp, struct termios *tio);
73 static void vcons_tty_start(struct tty *tp);
74 static void vcons_intr(void *tpx);
75
76 static d_open_t         vcons_open;
77 static d_close_t        vcons_close;
78 static d_ioctl_t        vcons_ioctl;
79
80 static struct dev_ops vcons_ops = {
81         { "vcons", CDEV_MAJOR, D_TTY },
82         .d_open =       vcons_open,
83         .d_close =      vcons_close,
84         .d_read =       ttyread,
85         .d_write =      ttywrite,
86         .d_ioctl =      vcons_ioctl,
87         .d_poll =       ttypoll,
88 };
89
90 static int
91 vcons_open(struct dev_open_args *ap)
92 {
93         cdev_t dev = ap->a_head.a_dev;
94         struct tty *tp;
95         int error;
96
97         if (minor(dev) != 255)
98                 return(ENXIO);
99
100         tp = dev->si_tty = ttymalloc(dev->si_tty);
101         if ((tp->t_state & TS_ISOPEN) == 0) {
102                 tp->t_oproc = vcons_tty_start;
103                 tp->t_param = vcons_tty_param;
104                 tp->t_stop = nottystop;
105                 tp->t_dev = dev;
106
107                 tp->t_state |= TS_CARR_ON | TS_CONNECTED;
108                 ttychars(tp);
109                 tp->t_iflag = TTYDEF_IFLAG;
110                 tp->t_oflag = TTYDEF_OFLAG;
111                 tp->t_cflag = TTYDEF_CFLAG;
112                 tp->t_lflag = TTYDEF_LFLAG;
113                 tp->t_ispeed = TTYDEF_SPEED;
114                 tp->t_ospeed = TTYDEF_SPEED;
115                 ttsetwater(tp);
116         }
117         error = (*linesw[tp->t_line].l_open)(dev, tp);
118         callout_reset(&console_callout, hz / 30 + 1, vcons_intr, tp);
119         return(error);
120 }
121
122 static int
123 vcons_close(struct dev_close_args *ap)
124 {
125         cdev_t dev = ap->a_head.a_dev;
126         struct tty *tp;
127
128         if (minor(dev) != 255)
129                 return(ENXIO);
130         tp = dev->si_tty;
131         (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
132         ttyclose(tp);
133         return(0);
134 }
135
136 static int
137 vcons_ioctl(struct dev_ioctl_args *ap)
138 {
139         cdev_t dev = ap->a_head.a_dev;
140         struct tty *tp;
141         int error;
142
143         if (minor(dev) != 255)
144                 return(ENXIO);
145         tp = dev->si_tty;
146         error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data,
147                                               ap->a_fflag, ap->a_cred);
148         if (error != ENOIOCTL)
149                 return (error);
150         error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag);
151         if (error != ENOIOCTL)
152                 return (error);
153         return (ENOTTY);
154 }
155
156 static int
157 vcons_tty_param(struct tty *tp, struct termios *tio)
158 {
159         tp->t_ispeed = tio->c_ispeed;
160         tp->t_ospeed = tio->c_ospeed;
161         tp->t_cflag = tio->c_cflag;
162         return(0);
163 }
164
165 static void
166 vcons_tty_start(struct tty *tp)
167 {
168         int n;
169         char buf[64];
170
171         if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
172                 ttwwakeup(tp);
173                 return;
174         }
175         tp->t_state |= TS_BUSY;
176         while ((n = q_to_b(&tp->t_outq, buf, sizeof(buf))) > 0)
177                 write(1, buf, n);
178         tp->t_state &= ~TS_BUSY;
179         ttwwakeup(tp);
180 }
181
182 static
183 void
184 vcons_intr(void *tpx)
185 {
186         struct tty *tp = tpx;
187         unsigned char buf[32];
188         int i;
189         int n;
190
191         /*
192          * If we aren't open we only have synchronous traffic via the
193          * debugger and do not need to poll.
194          */
195         if ((tp->t_state & TS_ISOPEN) == 0)
196                 return;
197
198         /*
199          * Only poll if we are open and haven't been stolen by the debugger.
200          */
201         if (console_stolen_by_kernel == 0 && (tp->t_state & TS_ISOPEN)) {
202                 do {
203                         n = extpread(0, buf, sizeof(buf), O_FNONBLOCKING, -1LL);
204                         for (i = 0; i < n; ++i)
205                                 (*linesw[tp->t_line].l_rint)(buf[i], tp);
206                 } while (n > 0);
207         }
208         callout_reset(&console_callout, hz / 30 + 1, vcons_intr, tp);
209 }
210
211 /************************************************************************
212  *                      KERNEL CONSOLE INTERFACE                        *
213  ************************************************************************
214  *
215  * Kernel direct-call interface console driver
216  */
217 static cn_probe_t       vconsprobe;
218 static cn_init_t        vconsinit;
219 static cn_term_t        vconsterm;
220 static cn_getc_t        vconsgetc;
221 static cn_checkc_t      vconscheckc;
222 static cn_putc_t        vconsputc;
223
224 CONS_DRIVER(vcons, vconsprobe, vconsinit, vconsterm, vconsgetc, 
225                 vconscheckc, vconsputc, NULL);
226
227 static void
228 vconsprobe(struct consdev *cp)
229 {
230         struct termios tio;
231
232         cp->cn_pri = CN_NORMAL;
233         cp->cn_dev = make_dev(&vcons_ops, 255,
234                               UID_ROOT, GID_WHEEL, 0600, "vconsolectl");
235
236         if (tcgetattr(0, &tio) == 0) {
237                 cfmakeraw(&tio);
238                 tio.c_lflag |= ISIG;
239                 tcsetattr(0, TCSAFLUSH, &tio);
240                 vcons_set_mode(0);
241         }
242         callout_init(&console_callout);
243 }
244
245 static void
246 vconsinit(struct consdev *cp)
247 {
248 }
249
250 static void
251 vconsterm(struct consdev *vp)
252 {
253 }
254
255 static int
256 vconsgetc(cdev_t dev)
257 {
258         unsigned char c;
259         ssize_t n;
260
261         console_stolen_by_kernel = 1;
262         for (;;) {
263                 if ((n = read(0, &c, 1)) == 1)
264                         break;
265                 if (n < 0 && errno == EINTR)
266                         continue;
267                 panic("vconsgetc: EOF on console %d %d", n ,errno);
268         }
269         console_stolen_by_kernel = 0;
270         return((int)c);
271 }
272
273 static int
274 vconscheckc(cdev_t dev)
275 {
276         unsigned char c;
277
278         if (extpread(0, &c, 1, O_FNONBLOCKING, -1LL) == 1)
279                 return((int)c);
280         return(-1);
281 }
282
283 static void
284 vconsputc(cdev_t dev, int c)
285 {
286         char cc = c;
287
288         write(1, &cc, 1);
289 }
290
291 void
292 vcons_set_mode(int in_debugger)
293 {
294         struct termios tio;
295
296         if (tcgetattr(0, &tio) < 0)
297                 return;
298         cfmakeraw(&tio);
299         tio.c_lflag |= ISIG;
300         if (in_debugger) {
301                 tio.c_cc[VINTR] = 'c' & 0x1f;
302                 tio.c_cc[VSUSP] = 'z' & 0x1f;
303                 tio.c_cc[VSTATUS] = 't' & 0x1f;
304         } else {
305                 tio.c_cc[VINTR] = 0;
306                 tio.c_cc[VSUSP] = 0;
307                 tio.c_cc[VSTATUS] = 0;
308         }
309         tcsetattr(0, TCSAFLUSH, &tio);
310 }
311
312
313