Add support for console over UDP (compatible to Ingo Molnar's
[platform/kernel/u-boot.git] / drivers / netconsole.c
1 /*
2  * (C) Copyright 2004
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25
26 #ifdef CONFIG_NETCONSOLE
27
28 #include <command.h>
29 #include <devices.h>
30 #include <net.h>
31
32 #ifndef CONFIG_NET_MULTI
33 #error define CONFIG_NET_MULTI to use netconsole
34 #endif
35
36 static uchar nc_buf = 0;        /* input buffer */
37 static int input_recursion = 0;
38 static int output_recursion = 0;
39 static int net_timeout;
40
41 static void nc_wait_arp_handler (uchar * pkt, unsigned dest, unsigned src,
42                                  unsigned len)
43 {
44         NetState = NETLOOP_SUCCESS;     /* got arp reply - quit net loop */
45 }
46
47 static void nc_handler (uchar * pkt, unsigned dest, unsigned src,
48                         unsigned len)
49 {
50         if (nc_buf)
51                 NetState = NETLOOP_SUCCESS;     /* got input - quit net loop */
52 }
53
54 static void nc_timeout (void)
55 {
56         NetState = NETLOOP_SUCCESS;
57 }
58
59 void NcStart (void)
60 {
61         if (memcmp (NetServerEther, NetEtherNullAddr, 6)) {
62                 /* going to check for input packet */
63                 NetSetHandler (nc_handler);
64                 NetSetTimeout (net_timeout, nc_timeout);
65         } else {
66                 /* send arp request */
67                 NetSetHandler (nc_wait_arp_handler);
68                 NetSendUDPPacket (NetServerEther, NetServerIP, 6665, 6666, 0);
69         }
70 }
71
72 int nc_input_packet (uchar * pkt, unsigned dest, unsigned src, unsigned len)
73 {
74         if (dest != 6666 || !len)
75                 return 0;               /* not for us */
76
77         nc_buf = *pkt;
78         return 1;
79 }
80
81 static void nc_send_packet (const char *buf, int len)
82 {
83         DECLARE_GLOBAL_DATA_PTR;
84
85         struct eth_device *eth;
86         int inited = 0;
87         uchar *pkt;
88
89         if (!memcmp (NetServerEther, NetEtherNullAddr, 6))
90                 return;
91
92         if ((eth = eth_get_dev ()) == NULL) {
93                 return;
94         }
95
96         if (eth->state != ETH_STATE_ACTIVE) {
97                 if (eth_init (gd->bd) < 0)
98                         return;
99                 inited = 1;
100         }
101         pkt = (uchar *) NetTxPacket + NetEthHdrSize () + IP_HDR_SIZE;
102         memcpy (pkt, buf, len);
103         NetSendUDPPacket (NetServerEther, NetServerIP, 6666, 6665, len);
104
105         if (inited)
106                 eth_halt ();
107 }
108
109 int nc_start (void)
110 {
111         if (memcmp (NetServerEther, NetEtherNullAddr, 6))
112                 return 0;
113
114         return NetLoop (NETCONS);       /* wait for arp reply */
115 }
116
117 void nc_putc (char c)
118 {
119         if (output_recursion)
120                 return;
121         output_recursion = 1;
122
123         nc_send_packet (&c, 1);
124
125         output_recursion = 0;
126 }
127
128 void nc_puts (const char *s)
129 {
130         if (output_recursion)
131                 return;
132         output_recursion = 1;
133
134         int len = strlen (s);
135
136         if (len > 512)
137                 len = 512;
138
139         nc_send_packet (s, len);
140
141         output_recursion = 0;
142 }
143
144 int nc_getc (void)
145 {
146         input_recursion = 1;
147
148         net_timeout = 0;        /* no timeout */
149         while (!nc_buf)
150                 NetLoop (NETCONS);
151
152         input_recursion = 0;
153
154         uchar tmp = nc_buf;
155
156         nc_buf = 0;
157         return tmp;
158 }
159
160 int nc_tstc (void)
161 {
162         struct eth_device *eth;
163
164         if (input_recursion)
165                 return 0;
166
167         if (nc_buf)
168                 return 1;
169
170         eth = eth_get_dev ();
171         if (eth && eth->state == ETH_STATE_ACTIVE)
172                 return 0;       /* inside net loop */
173
174         input_recursion = 1;
175
176         net_timeout = 1;
177         NetLoop (NETCONS);              /* kind of poll */
178
179         input_recursion = 0;
180
181         return nc_buf != 0;
182 }
183
184 int drv_nc_init (void)
185 {
186         device_t dev;
187         int rc;
188
189         memset (&dev, 0, sizeof (dev));
190
191         strcpy (dev.name, "nc");
192         dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
193         dev.start = nc_start;
194         dev.putc = nc_putc;
195         dev.puts = nc_puts;
196         dev.getc = nc_getc;
197         dev.tstc = nc_tstc;
198
199         rc = device_register (&dev);
200
201         return (rc == 0) ? 1 : rc;
202 }
203
204 #endif  /* CONFIG_NETCONSOLE */