Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
serial.c
Go to the documentation of this file.
1 /*
2  * Generic serial console support
3  *
4  * Author: Mark A. Greer <[email protected]>
5  *
6  * Code in serial_edit_cmdline() copied from <file:arch/ppc/boot/simple/misc.c>
7  * and was written by Matt Porter <[email protected]>.
8  *
9  * 2001,2006 (c) MontaVista Software, Inc. This file is licensed under
10  * the terms of the GNU General Public License version 2. This program
11  * is licensed "as is" without any warranty of any kind, whether express
12  * or implied.
13  */
14 #include <stdarg.h>
15 #include <stddef.h>
16 #include "types.h"
17 #include "string.h"
18 #include "stdio.h"
19 #include "io.h"
20 #include "ops.h"
21 
22 static int serial_open(void)
23 {
24  struct serial_console_data *scdp = console_ops.data;
25  return scdp->open();
26 }
27 
28 static void serial_write(const char *buf, int len)
29 {
30  struct serial_console_data *scdp = console_ops.data;
31 
32  while (*buf != '\0')
33  scdp->putc(*buf++);
34 }
35 
36 static void serial_edit_cmdline(char *buf, int len)
37 {
38  int timer = 0, count;
39  char ch, *cp;
40  struct serial_console_data *scdp = console_ops.data;
41 
42  cp = buf;
43  count = strlen(buf);
44  cp = &buf[count];
45  count++;
46 
47  while (timer++ < 5*1000) {
48  if (scdp->tstc()) {
49  while (((ch = scdp->getc()) != '\n') && (ch != '\r')) {
50  /* Test for backspace/delete */
51  if ((ch == '\b') || (ch == '\177')) {
52  if (cp != buf) {
53  cp--;
54  count--;
55  printf("\b \b");
56  }
57  /* Test for ^x/^u (and wipe the line) */
58  } else if ((ch == '\030') || (ch == '\025')) {
59  while (cp != buf) {
60  cp--;
61  count--;
62  printf("\b \b");
63  }
64  } else if (count < len) {
65  *cp++ = ch;
66  count++;
67  scdp->putc(ch);
68  }
69  }
70  break; /* Exit 'timer' loop */
71  }
72  udelay(1000); /* 1 msec */
73  }
74  *cp = 0;
75 }
76 
77 static void serial_close(void)
78 {
79  struct serial_console_data *scdp = console_ops.data;
80 
81  if (scdp->close)
82  scdp->close();
83 }
84 
85 static void *serial_get_stdout_devp(void)
86 {
87  void *devp;
88  char devtype[MAX_PROP_LEN];
89  char path[MAX_PATH_LEN];
90 
91  devp = finddevice("/chosen");
92  if (devp == NULL)
93  goto err_out;
94 
95  if (getprop(devp, "linux,stdout-path", path, MAX_PATH_LEN) > 0) {
96  devp = finddevice(path);
97  if (devp == NULL)
98  goto err_out;
99 
100  if ((getprop(devp, "device_type", devtype, sizeof(devtype)) > 0)
101  && !strcmp(devtype, "serial"))
102  return devp;
103  }
104 err_out:
105  return NULL;
106 }
107 
108 static struct serial_console_data serial_cd;
109 
110 /* Node's "compatible" property determines which serial driver to use */
112 {
113  void *devp;
114  int rc = -1;
115 
116  devp = serial_get_stdout_devp();
117  if (devp == NULL)
118  goto err_out;
119 
120  if (dt_is_compatible(devp, "ns16550") ||
121  dt_is_compatible(devp, "pnpPNP,501"))
122  rc = ns16550_console_init(devp, &serial_cd);
123  else if (dt_is_compatible(devp, "marvell,mv64360-mpsc"))
124  rc = mpsc_console_init(devp, &serial_cd);
125  else if (dt_is_compatible(devp, "fsl,cpm1-scc-uart") ||
126  dt_is_compatible(devp, "fsl,cpm1-smc-uart") ||
127  dt_is_compatible(devp, "fsl,cpm2-scc-uart") ||
128  dt_is_compatible(devp, "fsl,cpm2-smc-uart"))
129  rc = cpm_console_init(devp, &serial_cd);
130  else if (dt_is_compatible(devp, "fsl,mpc5200-psc-uart"))
131  rc = mpc5200_psc_console_init(devp, &serial_cd);
132  else if (dt_is_compatible(devp, "xlnx,opb-uartlite-1.00.b") ||
133  dt_is_compatible(devp, "xlnx,xps-uartlite-1.00.a"))
134  rc = uartlite_console_init(devp, &serial_cd);
135 
136  /* Add other serial console driver calls here */
137 
138  if (!rc) {
139  console_ops.open = serial_open;
140  console_ops.write = serial_write;
141  console_ops.close = serial_close;
142  console_ops.data = &serial_cd;
143 
144  if (serial_cd.getc)
145  console_ops.edit_cmdline = serial_edit_cmdline;
146 
147  return 0;
148  }
149 err_out:
150  return -1;
151 }