Merge from vendor branch INTEL_ACPICA:
[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.10 2007/01/15 05:27:31 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 kqueue_info *kqueue_console_info;
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, struct intrframe *frame __unused);
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         if (kqueue_console_info == NULL)
119                 kqueue_console_info = kqueue_add(0, vcons_intr, tp);
120         return(error);
121 }
122
123 static int
124 vcons_close(struct dev_close_args *ap)
125 {
126         cdev_t dev = ap->a_head.a_dev;
127         struct tty *tp;
128
129         if (minor(dev) != 255)
130                 return(ENXIO);
131         tp = dev->si_tty;
132         (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
133         ttyclose(tp);
134         return(0);
135 }
136
137 static int
138 vcons_ioctl(struct dev_ioctl_args *ap)
139 {
140         cdev_t dev = ap->a_head.a_dev;
141         struct tty *tp;
142         int error;
143
144         if (minor(dev) != 255)
145                 return(ENXIO);
146         tp = dev->si_tty;
147         error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data,
148                                               ap->a_fflag, ap->a_cred);
149         if (error != ENOIOCTL)
150                 return (error);
151         error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag);
152         if (error != ENOIOCTL)
153                 return (error);
154         return (ENOTTY);
155 }
156
157 static int
158 vcons_tty_param(struct tty *tp, struct termios *tio)
159 {
160         tp->t_ispeed = tio->c_ispeed;
161         tp->t_ospeed = tio->c_ospeed;
162         tp->t_cflag = tio->c_cflag;
163         return(0);
164 }
165
166 static void
167 vcons_tty_start(struct tty *tp)
168 {
169         int n;
170         char buf[64];
171
172         if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
173                 ttwwakeup(tp);
174                 return;
175         }
176         tp->t_state |= TS_BUSY;
177         while ((n = q_to_b(&tp->t_outq, buf, sizeof(buf))) > 0)
178                 write(1, buf, n);
179         tp->t_state &= ~TS_BUSY;
180         ttwwakeup(tp);
181 }
182
183 static
184 void
185 vcons_intr(void *tpx, struct intrframe *frame __unused)
186 {
187         struct tty *tp = tpx;
188         unsigned char buf[32];
189         int i;
190         int n;
191
192         /*
193          * If we aren't open we only have synchronous traffic via the
194          * debugger and do not need to poll.
195          */
196         if ((tp->t_state & TS_ISOPEN) == 0)
197                 return;
198
199         /*
200          * Only poll if we are open and haven't been stolen by the debugger.
201          */
202         if (console_stolen_by_kernel == 0 && (tp->t_state & TS_ISOPEN)) {
203                 do {
204                         n = extpread(0, buf, sizeof(buf), O_FNONBLOCKING, -1LL);
205                         for (i = 0; i < n; ++i)
206                                 (*linesw[tp->t_line].l_rint)(buf[i], tp);
207                 } while (n > 0);
208         }
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 }
243
244 static void
245 vconsinit(struct consdev *cp)
246 {
247 }
248
249 static void
250 vconsterm(struct consdev *vp)
251 {
252 }
253
254 static int
255 vconsgetc(cdev_t dev)
256 {
257         unsigned char c;
258         ssize_t n;
259
260         console_stolen_by_kernel = 1;
261         for (;;) {
262                 if ((n = read(0, &c, 1)) == 1)
263                         break;
264                 if (n < 0 && errno == EINTR)
265                         continue;
266                 panic("vconsgetc: EOF on console %d %d", n ,errno);
267         }
268         console_stolen_by_kernel = 0;
269         return((int)c);
270 }
271
272 static int
273 vconscheckc(cdev_t dev)
274 {
275         unsigned char c;
276
277         if (extpread(0, &c, 1, O_FNONBLOCKING, -1LL) == 1)
278                 return((int)c);
279         return(-1);
280 }
281
282 static void
283 vconsputc(cdev_t dev, int c)
284 {
285         char cc = c;
286
287         write(1, &cc, 1);
288 }
289
290 void
291 vcons_set_mode(int in_debugger)
292 {
293         struct termios tio;
294
295         if (tcgetattr(0, &tio) < 0)
296                 return;
297         cfmakeraw(&tio);
298         tio.c_lflag |= ISIG;
299         if (in_debugger) {
300                 tio.c_cc[VINTR] = 'c' & 0x1f;
301                 tio.c_cc[VSUSP] = 'z' & 0x1f;
302                 tio.c_cc[VSTATUS] = 't' & 0x1f;
303         } else {
304                 tio.c_cc[VINTR] = _POSIX_VDISABLE;
305                 tio.c_cc[VSUSP] = _POSIX_VDISABLE;
306                 tio.c_cc[VSTATUS] = _POSIX_VDISABLE;
307         }
308         tcsetattr(0, TCSAFLUSH, &tio);
309 }
310
311
312