Merge branch 'support_for_ar9341'
[oweals/u-boot_mod.git] / u-boot / 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 #include <common.h>
24
25 #ifdef CONFIG_NETCONSOLE
26 #include <command.h>
27 #include <devices.h>
28 #include <net.h>
29
30 DECLARE_GLOBAL_DATA_PTR;
31
32 static char input_buffer[512];
33 static int input_size = 0;                      /* char count in input buffer */
34 static int input_offset = 0;            /* offset to valid chars in input buffer */
35 static int input_recursion = 0;
36 static int output_recursion = 0;
37 static int net_timeout;
38 static uchar nc_ether[6];                       /* server enet address */
39 static IPaddr_t nc_ip;                          /* server ip */
40 static short nc_port;                           /* source/target port */
41 static const char *output_packet;       /* used by first send udp */
42 static int output_packet_len = 0;
43
44 /*
45  * Start with a default last protocol.
46  * We are only interested in NETCONS or not.
47  */
48 proto_t net_loop_last_protocol = BOOTP;
49
50 static void nc_wait_arp_handler(uchar * pkt, unsigned dest, unsigned src, unsigned len){
51         NetState = NETLOOP_SUCCESS; /* got arp reply - quit net loop */
52 }
53
54 static void nc_handler(uchar * pkt, unsigned dest, unsigned src, unsigned len){
55         if(input_size){ /* got input - quit net loop */
56                 NetState = NETLOOP_SUCCESS;
57         }
58 }
59
60 static void nc_timeout(void){
61         NetState = NETLOOP_SUCCESS;
62 }
63
64 void NcStart(void){
65         if(!output_packet_len || memcmp(nc_ether, NetEtherNullAddr, 6)){
66                 /* going to check for input packet */
67                 NetSetHandler(nc_handler);
68                 NetSetTimeout(net_timeout, nc_timeout);
69         } else {
70                 /* send arp request */
71                 uchar *pkt;
72                 NetSetHandler(nc_wait_arp_handler);
73                 pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE;
74                 memcpy(pkt, output_packet, output_packet_len);
75                 NetSendUDPPacket(nc_ether, nc_ip, nc_port, nc_port, output_packet_len);
76         }
77 }
78
79 int nc_input_packet(uchar * pkt, unsigned dest, unsigned src, unsigned len){
80         int end, chunk;
81
82         if(dest != nc_port || !len){ /* not for us */
83                 return(0);
84         }
85
86         if(input_size == sizeof(input_buffer)){ /* no space */
87                 return(1);
88         }
89
90         if(len > sizeof input_buffer - input_size){
91                 len = sizeof input_buffer - input_size;
92         }
93
94         end = input_offset + input_size;
95
96         if(end > sizeof input_buffer){
97                 end -= sizeof input_buffer;
98         }
99
100         chunk = len;
101
102         if(end + len > sizeof input_buffer){
103                 chunk = sizeof input_buffer - end;
104                 memcpy(input_buffer, pkt + chunk, len - chunk);
105         }
106
107         memcpy(input_buffer + end, pkt, chunk);
108
109         input_size += len;
110
111         return(1);
112 }
113
114 static void nc_send_packet(const char *buf, int len){
115         struct eth_device *eth;
116         int inited = 0;
117         uchar *pkt;
118         uchar *ether;
119         IPaddr_t ip;
120
121         if((eth = eth_get_dev()) == NULL){
122                 return;
123         }
124
125         if(!memcmp(nc_ether, NetEtherNullAddr, 6)){
126                 if(eth->state == ETH_STATE_ACTIVE){
127                         return;
128                 }
129
130                 output_packet = buf;
131                 output_packet_len = len;
132                 NetLoop(NETCONS); /* wait for arp reply and send packet */
133                 output_packet_len = 0;
134
135                 return;
136         }
137
138         if(eth->state != ETH_STATE_ACTIVE){
139                 if(eth_is_on_demand_init()){
140                         if(eth_init(gd->bd) < 0){
141                                 return;
142                         }
143                         eth_set_last_protocol(NETCONS);
144                 } else {
145                         eth_init_state_only(gd->bd);
146                 }
147
148                 inited = 1;
149         }
150
151         pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE;
152         memcpy(pkt, buf, len);
153         ether = nc_ether;
154         ip = nc_ip;
155         NetSendUDPPacket(ether, ip, nc_port, nc_port, len);
156
157         if(inited){
158                 if(eth_is_on_demand_init()){
159                         eth_halt();
160                 } else {
161                         eth_halt_state_only();
162                 }
163         }
164 }
165
166 int nc_start(void){
167         int netmask, our_ip;
168         char *p;
169
170         p = getenv("ncport");
171         nc_port = p ? (short)simple_strtol(p, NULL, 10) : 6666; /* default NetConsole port */
172
173         if(getenv("serverip")){
174
175                 nc_ip = getenv_IPaddr("serverip");
176
177                 if(!nc_ip){
178                         return(-1);
179                 }
180
181         } else {
182                 nc_ip = ~0; /* ncip is not set */
183         }
184
185         our_ip = getenv_IPaddr("ipaddr");
186         netmask = getenv_IPaddr("netmask");
187
188         if(nc_ip == ~0 || /* 255.255.255.255 */
189            ((netmask & our_ip) == (netmask & nc_ip) && /* on the same net */
190            (netmask | nc_ip) == ~0)) /* broadcast to our net */{
191                 memset(nc_ether, 0xff, sizeof nc_ether);
192         } else {
193                 memset(nc_ether, 0, sizeof nc_ether); /* force arp request */
194         }
195
196         return(0);
197 }
198
199 void nc_putc(char c){
200         if(output_recursion){
201                 return;
202         }
203
204         output_recursion = 1;
205
206         nc_send_packet(&c, 1);
207
208         output_recursion = 0;
209 }
210
211 void nc_puts(const char *s){
212         int len;
213
214         if(output_recursion){
215                 return;
216         }
217
218         output_recursion = 1;
219
220         if((len = strlen(s)) > 512){
221                 len = 512;
222         }
223
224         nc_send_packet(s, len);
225
226         output_recursion = 0;
227 }
228
229 int nc_getc(void){
230         uchar c;
231
232         input_recursion = 1;
233
234         net_timeout = 0; /* no timeout */
235         while(!input_size){
236                 NetLoop(NETCONS);
237         }
238
239         input_recursion = 0;
240
241         c = input_buffer[input_offset++];
242
243         if(input_offset >= sizeof input_buffer){
244                 input_offset -= sizeof input_buffer;
245         }
246
247         input_size--;
248
249         return(c);
250 }
251
252 int nc_tstc(void){
253         struct eth_device *eth;
254
255         if(input_recursion){
256                 return(0);
257         }
258
259         if(input_size){
260                 return(1);
261         }
262
263         eth = eth_get_dev();
264
265         if(eth && eth->state == ETH_STATE_ACTIVE){
266                 return(0); /* inside net loop */
267         }
268
269         input_recursion = 1;
270
271         net_timeout = 1;
272         NetLoop(NETCONS); /* kind of poll */
273
274         input_recursion = 0;
275
276         return(input_size != 0);
277 }
278
279 int drv_nc_init(void){
280         device_t dev;
281         int rc;
282
283         memset(&dev, 0, sizeof(dev));
284
285         strcpy(dev.name, "nc");
286         dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
287         dev.start = nc_start;
288         dev.putc = nc_putc;
289         dev.puts = nc_puts;
290         dev.getc = nc_getc;
291         dev.tstc = nc_tstc;
292
293         rc = device_register(&dev);
294
295         return((rc == 0) ? 1 : rc);
296 }
297
298 #endif  /* CONFIG_NETCONSOLE */