~smartboyhw/wubi/bug-1080090-new

« back to all changes in this revision

Viewing changes to src/grub4dos/stage2/.svn/text-base/serial.c.svn-base

  • Committer: Howard Chan
  • Date: 2012-11-20 10:16:05 UTC
  • Revision ID: smartboyhw@gmail.com-20121120101605-qfmjfsdynpzg9an9
Added images

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* serial.c - serial device interface */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
5
 
 *
6
 
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; either version 2 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  This program is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with this program; if not, write to the Free Software
18
 
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 
 */
20
 
 
21
 
#ifdef SUPPORT_SERIAL
22
 
 
23
 
#include <shared.h>
24
 
#include <serial.h>
25
 
#include <term.h>
26
 
#include <terminfo.h>
27
 
 
28
 
/* An input buffer.  */
29
 
static char input_buf[8];
30
 
static int npending = 0;
31
 
 
32
 
static int serial_x;
33
 
static int serial_y;
34
 
 
35
 
static int keep_track = 1;
36
 
 
37
 
 
38
 
/* Hardware-dependent definitions.  */
39
 
 
40
 
#ifndef GRUB_UTIL
41
 
/* The structure for speed vs. divisor.  */
42
 
struct divisor
43
 
{
44
 
  int speed;
45
 
  unsigned short div;
46
 
};
47
 
 
48
 
/* Store the port number of a serial unit.  */
49
 
static unsigned short serial_hw_port = 0;
50
 
 
51
 
/* The table which lists common configurations.  */
52
 
static struct divisor divisor_tab[] =
53
 
  {
54
 
    { 2400,   0x0030 },
55
 
    { 4800,   0x0018 },
56
 
    { 9600,   0x000C },
57
 
    { 19200,  0x0006 },
58
 
    { 38400,  0x0003 },
59
 
    { 57600,  0x0002 },
60
 
    { 115200, 0x0001 }
61
 
  };
62
 
 
63
 
/* Read a byte from a port.  */
64
 
static inline unsigned char
65
 
inb (unsigned short port)
66
 
{
67
 
  unsigned char value;
68
 
 
69
 
  asm volatile ("inb    %w1, %0" : "=a" (value) : "Nd" (port));
70
 
  asm volatile ("outb   %%al, $0x80" : : );
71
 
  
72
 
  return value;
73
 
}
74
 
 
75
 
/* Write a byte to a port.  */
76
 
static inline void
77
 
outb (unsigned short port, unsigned char value)
78
 
{
79
 
  asm volatile ("outb   %b0, %w1" : : "a" (value), "Nd" (port));
80
 
  asm volatile ("outb   %%al, $0x80" : : );
81
 
}
82
 
 
83
 
/* Fetch a key.  */
84
 
int
85
 
serial_hw_fetch (void)
86
 
{
87
 
  if (inb (serial_hw_port + UART_LSR) & UART_DATA_READY)
88
 
    return inb (serial_hw_port + UART_RX);
89
 
 
90
 
  return -1;
91
 
}
92
 
 
93
 
/* Put a chararacter.  */
94
 
void
95
 
serial_hw_put (int c)
96
 
{
97
 
  int timeout = 100000;
98
 
 
99
 
  /* Wait until the transmitter holding register is empty.  */
100
 
  while ((inb (serial_hw_port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
101
 
    {
102
 
      if (--timeout == 0)
103
 
        /* There is something wrong. But what can I do?  */
104
 
        return;
105
 
    }
106
 
 
107
 
  outb (serial_hw_port + UART_TX, c);
108
 
}
109
 
 
110
 
void
111
 
serial_hw_delay (void)
112
 
{
113
 
  outb (0x80, 0);
114
 
}
115
 
 
116
 
/* Return the port number for the UNITth serial device.  */
117
 
unsigned short
118
 
serial_hw_get_port (int unit)
119
 
{
120
 
  /* The BIOS data area.  */
121
 
  const unsigned short *addr = (const unsigned short *) 0x0400;
122
 
  
123
 
  return addr[unit];
124
 
}
125
 
 
126
 
/* Initialize a serial device. PORT is the port number for a serial device.
127
 
   SPEED is a DTE-DTE speed which must be one of these: 2400, 4800, 9600,
128
 
   19200, 38400, 57600 and 115200. WORD_LEN is the word length to be used
129
 
   for the device. Likewise, PARITY is the type of the parity and
130
 
   STOP_BIT_LEN is the length of the stop bit. The possible values for
131
 
   WORD_LEN, PARITY and STOP_BIT_LEN are defined in the header file as
132
 
   macros.  */
133
 
int
134
 
serial_hw_init (unsigned short port, unsigned int speed,
135
 
                int word_len, int parity, int stop_bit_len)
136
 
{
137
 
  int i;
138
 
  unsigned short div = 0;
139
 
  unsigned char status = 0;
140
 
  
141
 
  /* Turn off the interrupt.  */
142
 
  outb (port + UART_IER, 0);
143
 
 
144
 
  /* Set DLAB.  */
145
 
  outb (port + UART_LCR, UART_DLAB);
146
 
  
147
 
  /* Set the baud rate.  */
148
 
  for (i = 0; i < sizeof (divisor_tab) / sizeof (divisor_tab[0]); i++)
149
 
    if (divisor_tab[i].speed == speed)
150
 
      {
151
 
        div = divisor_tab[i].div;
152
 
        break;
153
 
      }
154
 
  
155
 
  if (div == 0)
156
 
    return 0;
157
 
  
158
 
  outb (port + UART_DLL, div & 0xFF);
159
 
  outb (port + UART_DLH, div >> 8);
160
 
  
161
 
  /* Set the line status.  */
162
 
  status |= parity | word_len | stop_bit_len;
163
 
  outb (port + UART_LCR, status);
164
 
 
165
 
  /* Enable the FIFO.  */
166
 
  outb (port + UART_FCR, UART_ENABLE_FIFO);
167
 
 
168
 
  /* Turn on DTR, RTS, and OUT2.  */
169
 
  outb (port + UART_MCR, UART_ENABLE_MODEM);
170
 
 
171
 
  /* Store the port number.  */
172
 
  serial_hw_port = port;
173
 
  
174
 
  /* Drain the input buffer.  */
175
 
  while (serial_checkkey () != -1)
176
 
    (void) serial_getkey ();
177
 
 
178
 
  /* Get rid of TERM_NEED_INIT from the serial terminal.  */
179
 
  for (i = 0; term_table[i].name; i++)
180
 
    if (grub_strcmp (term_table[i].name, "serial") == 0)
181
 
      {
182
 
        term_table[i].flags &= ~TERM_NEED_INIT;
183
 
        break;
184
 
      }
185
 
 
186
 
  /* FIXME: should check if the serial terminal was found.  */
187
 
  
188
 
  return 1;
189
 
}
190
 
#endif /* ! GRUB_UTIL */
191
 
 
192
 
 
193
 
/*              Table of Serial Terminal Escape Sequences
194
 
 *=======================================================================
195
 
 *  Key          ANSI           VT100 extension         VT220 extension
196
 
 * ---------    -------         ---------------         ---------------
197
 
 * Up arrow     <Esc>[A
198
 
 * Down arrow   <Esc>[B
199
 
 * Right arrow  <Esc>[C
200
 
 * Left arrow   <Esc>[D
201
 
 * F1           <Esc>Op 
202
 
 * F2           <Esc>Oq 
203
 
 * F3           <Esc>Or 
204
 
 * F4           <Esc>Os 
205
 
 * F5           <Esc>Ot 
206
 
 * F6           <Esc>Ou         <Esc>[17~               <Esc>[17~
207
 
 * F7           <Esc>Ov         <Esc>[18~               <Esc>[18~
208
 
 * F8           <Esc>Ow         <Esc>[19~               <Esc>[19~
209
 
 * F9           <Esc>Ox         <Esc>[20~               <Esc>[20~
210
 
 * F10          <Esc>Oy         <Esc>[21~               <Esc>[21~
211
 
 * F11          <Esc>Oz         <Esc>[23~               <Esc>[23~
212
 
 * F12          <Esc>Oa         <Esc>[24~               <Esc>[24~
213
 
 * Home                                                 <Esc>[1~
214
 
 * End                                                  <Esc>[4~
215
 
 * Insert                                               <Esc>[2~
216
 
 * Delete                                               <Esc>[3~
217
 
 * Page Up                                              <Esc>[5~
218
 
 * Page Down                                            <Esc>[6~
219
 
 * Shift-Tab                    <Esc>[Z                 <Esc>[0Z
220
 
 */
221
 
 
222
 
/* Generic definitions.  */
223
 
 
224
 
static void
225
 
serial_translate_key_sequence (void)
226
 
{
227
 
  const struct
228
 
  {
229
 
    short /*char*/ key;
230
 
    short /*char*/ ascii;
231
 
  }
232
 
  three_code_table[] =
233
 
    {
234
 
      {'A', KEY_UP/*16*/},              /* Up arrow */
235
 
      {'B', KEY_DOWN/*14*/},            /* Down arrow */
236
 
      {'C', KEY_RIGHT/*6*/},            /* Right arrow */
237
 
      {'D', KEY_LEFT/*2*/},             /* Left arrow */
238
 
      {'F', KEY_END/*5*/},              /* End */
239
 
      {'H', KEY_HOME/*1*/},             /* Home */
240
 
      {'4', KEY_DC/*4*/}                /* Delete */
241
 
    };
242
 
 
243
 
  const struct
244
 
  {
245
 
    short key;
246
 
    short /*char*/ ascii;
247
 
  }
248
 
  four_code_table[] =
249
 
    {
250
 
      {('1' | ('~' << 8)), KEY_HOME/*1*/},      /* Home */
251
 
      {('3' | ('~' << 8)), KEY_DC/*4*/},        /* Delete */
252
 
      {('5' | ('~' << 8)), KEY_PPAGE/*7*/},     /* Page Up */
253
 
      {('6' | ('~' << 8)), KEY_NPAGE/*3*/},     /* Page Down */
254
 
    };
255
 
  
256
 
  /* The buffer must start with ``ESC [''.  */
257
 
  if (*((unsigned short *) input_buf) != ('\e' | ('[' << 8)))
258
 
    return;
259
 
  
260
 
  if (npending >= 3)
261
 
    {
262
 
      int i;
263
 
 
264
 
      for (i = 0;
265
 
           i < sizeof (three_code_table) / sizeof (three_code_table[0]);
266
 
           i++)
267
 
        if (three_code_table[i].key == input_buf[2])
268
 
          {
269
 
            *(short *)input_buf = three_code_table[i].ascii;
270
 
            npending--;//npending -= 2;
271
 
            grub_memmove (input_buf + 2/*1*/, input_buf + 3, npending - 2/*1*/);
272
 
            return;
273
 
          }
274
 
    }
275
 
 
276
 
  if (npending >= 4)
277
 
    {
278
 
      int i;
279
 
      short key = *((short *) (input_buf + 2));
280
 
 
281
 
      for (i = 0;
282
 
           i < sizeof (four_code_table) / sizeof (four_code_table[0]);
283
 
           i++)
284
 
        if (four_code_table[i].key == key)
285
 
          {
286
 
            *(short *)input_buf = four_code_table[i].ascii;
287
 
            npending -= 2/*3*/;
288
 
            grub_memmove (input_buf + 2/*1*/, input_buf + 4, npending - 2/*1*/);
289
 
            return;
290
 
          }
291
 
    }
292
 
}
293
 
    
294
 
static int
295
 
fill_input_buf (int nowait)
296
 
{
297
 
  int i;
298
 
 
299
 
  for (i = 0; i < 10000 && npending < sizeof (input_buf); i++)
300
 
    {
301
 
      int c;
302
 
 
303
 
      c = serial_hw_fetch ();
304
 
      if (c >= 0)
305
 
        {
306
 
          input_buf[npending++] = c;
307
 
 
308
 
          /* Reset the counter to zero, to wait for the same interval.  */
309
 
          i = 0;
310
 
        }
311
 
      
312
 
      if (nowait)
313
 
        break;
314
 
    }
315
 
 
316
 
  /* Translate some key sequences.  */
317
 
  serial_translate_key_sequence ();
318
 
          
319
 
  return npending;
320
 
}
321
 
 
322
 
/* The serial version of getkey.  */
323
 
int
324
 
serial_getkey (void)
325
 
{
326
 
  int c;
327
 
  
328
 
  while (! fill_input_buf (0))
329
 
    ;
330
 
 
331
 
  npending--;
332
 
  if ((c = input_buf[0]))
333
 
        grub_memmove (input_buf, input_buf + 1, npending);
334
 
  else
335
 
  {
336
 
        npending--;
337
 
        c = *(unsigned short *)input_buf;
338
 
        grub_memmove (input_buf, input_buf + 2, npending);
339
 
  }
340
 
  
341
 
  return c;
342
 
}
343
 
 
344
 
/* The serial version of checkkey.  */
345
 
int
346
 
serial_checkkey (void)
347
 
{
348
 
  if (fill_input_buf (1))
349
 
    return input_buf[0] ? input_buf[0] : *(unsigned short *)input_buf;
350
 
 
351
 
  return -1;
352
 
}
353
 
 
354
 
/* The serial version of grub_putchar.  */
355
 
void
356
 
serial_putchar (int c)
357
 
{
358
 
  /* Keep track of the cursor.  */
359
 
  if (keep_track)
360
 
    {
361
 
#if 0
362
 
      /* The serial terminal doesn't have VGA fonts.  */
363
 
      switch (c)
364
 
        {
365
 
        case DISP_UL:
366
 
          c = ACS_ULCORNER;
367
 
          break;
368
 
        case DISP_UR:
369
 
          c = ACS_URCORNER;
370
 
          break;
371
 
        case DISP_LL:
372
 
          c = ACS_LLCORNER;
373
 
          break;
374
 
        case DISP_LR:
375
 
          c = ACS_LRCORNER;
376
 
          break;
377
 
        case DISP_HORIZ:
378
 
          c = ACS_HLINE;
379
 
          break;
380
 
        case DISP_VERT:
381
 
          c = ACS_VLINE;
382
 
          break;
383
 
        case DISP_LEFT:
384
 
          c = ACS_LARROW;
385
 
          break;
386
 
        case DISP_RIGHT:
387
 
          c = ACS_RARROW;
388
 
          break;
389
 
        case DISP_UP:
390
 
          c = ACS_UARROW;
391
 
          break;
392
 
        case DISP_DOWN:
393
 
          c = ACS_DARROW;
394
 
          break;
395
 
        default:
396
 
          break;
397
 
        }
398
 
#endif
399
 
      
400
 
      switch (c)
401
 
        {
402
 
        case '\r':
403
 
          serial_x = 0;
404
 
          break;
405
 
          
406
 
        case '\n':
407
 
          serial_y++;
408
 
          break;
409
 
          
410
 
        case '\b':
411
 
        case 127:
412
 
          if (serial_x > 0)
413
 
            serial_x--;
414
 
          break;
415
 
          
416
 
        case '\a':
417
 
          break;
418
 
          
419
 
        default:
420
 
          if (serial_x >= 79)
421
 
            {
422
 
              serial_putchar ('\r');
423
 
              serial_putchar ('\n');
424
 
            }
425
 
          serial_x++;
426
 
          break;
427
 
        }
428
 
    }
429
 
  
430
 
  serial_hw_put (c);
431
 
}
432
 
 
433
 
int
434
 
serial_getxy (void)
435
 
{
436
 
  return (serial_x << 8) | serial_y;
437
 
}
438
 
 
439
 
void
440
 
serial_gotoxy (int x, int y)
441
 
{
442
 
  keep_track = 0;
443
 
  ti_cursor_address (x, y);
444
 
  keep_track = 1;
445
 
  
446
 
  serial_x = x;
447
 
  serial_y = y;
448
 
}
449
 
 
450
 
void
451
 
serial_cls (void)
452
 
{
453
 
  keep_track = 0;
454
 
  ti_clear_screen ();
455
 
  keep_track = 1;
456
 
  
457
 
  serial_x = serial_y = 0;
458
 
}
459
 
 
460
 
void
461
 
serial_setcolorstate (color_state state)
462
 
{
463
 
  keep_track = 0;
464
 
  if (state == COLOR_STATE_HIGHLIGHT)
465
 
    ti_enter_standout_mode ();
466
 
  else
467
 
    ti_exit_standout_mode ();
468
 
  keep_track = 1;
469
 
}
470
 
 
471
 
#endif /* SUPPORT_SERIAL */